روشی که forwardRef در تایپ اسکریپت پیادهسازی میشود دارای محدودیتهایی میباشد که بزرگترین آن این است که استنتاج تایپ را در کامپوننتهای Generic غیرفعال میکند. در این مقاله قصد داریم تا استفاده از forwardRef در کامپوننتهای Generic را باهم بررسی نماییم.
یکی از موارد استفاده رایج از کامپوننتهای Generic، مفهوم Table
است:
const Table = <T,>(props: { data: T[]; renderRow: (row: T) => React.ReactNode; }) => { return ( <table> <tbody> {props.data.map((item, index) => ( <props.renderRow key={index} {...item} /> ))} </tbody> </table> ); };
در مثال بالا، هنگامی که ما آرایهای از هر چیزی را به data
ارسال میکنیم، آن آرایه در آرگومان ارسال شده به تابع renderRow
استنتاج تایپ را انجام میدهد.
<Table // ۱٫ Data is a string here... data={["a", "b"]} // ۲٫ So ends up inferring as a string in renderRow. renderRow={(row) => { (parameter) row: string return <tr>{row}</tr>; }} />; <Table // ۳٫ Data is a number here... data={[1, 2]} // ۴٫ So ends up inferring as a number in renderRow. renderRow={(row) => { (parameter) row: number return <tr>{row}</tr>; }} />;
این موضوع واقعا مفید است، زیرا به این معنی میباشد که ما میتوانیم بدون نوشتن هیچگونه annotation اضافی، استنتاج تایپ را در تابع renderRow
انجام دهیم.
زمانی که ما سعی میکنیم تا یک ref
را به کامپوننت Table
خود اضافه کنیم، محدودیت و مشکل مربوط به forwardRef مطرح میشود:
const Table = <T,>( props: { data: T[]; renderRow: (row: T) => React.ReactNode; }, ref: React.ForwardedRef<HTMLTableElement> ) => { return ( <table ref={ref}> <tbody> {props.data.map((item, index) => ( <props.renderRow key={index} {...item} /> ))} </tbody> </table> ); }; const ForwardReffedTable = React.forwardRef(Table);
کدی که داریم در نگاه اول درست به نظر میرسد، اما وقتی از کامپوننت ForwardReffedTable
استفاده میکنیم استنتاجی که قبلاً دیدیم دیگر کار نمیکند.
<ForwardReffedTable // ۱٫ Data is a string here... data={["a", "b"]} // ۲٫ But ends up being inferred as unknown. renderRow={(row) => { (parameter) row: unknown return <tr />; }} />; <ForwardReffedTable // ۳٫ Data is a number here... data={[1, 2]} // ۴٫ But still ends up being inferred as unknown. renderRow={(row) => { (parameter) row: unknown return <tr />; }} />;
این موضوع میتواند مشکلات زیادی را در برنامه ما ایجاد کند. اما ما میتوانیم آن را برطرف نماییم.
ما میتوانیم با استفاده از یک تعریف تایپ دیگر، forwardRef را دوباره تعریف نماییم و در نتیجه، محدودیت استفاده از آن را برطرف کنیم.
در مثال زیر تعریف جدید را اضافه میکنیم:
function fixedForwardRef<T, P = {}>( render: (props: P, ref: React.Ref<T>) => React.ReactNode ): (props: P & React.RefAttributes<T>) => React.ReactNode { return React.forwardRef(render) as any; }
میتوانیم تعریف خود را برای استفاده از fixedForwardRef
تغییر دهیم:
const ForwardReffedTable = fixedForwardRef(Table);
به این ترتیب، مشاهده میکنیم کدی که داریم به درستی شروع به کار میکند:
<ForwardReffedTable data={["a", "b"]} renderRow={(row) => { (parameter) row: string return <tr />; }} />; <ForwardReffedTable data={[1, 2]} renderRow={(row) => { (parameter) row: number return <tr />; }} />;
در این مقاله سعی کردیم تا مفهوم Generic و forwardRef در تایپ اسکریپت را بررسی کنیم و همچنین با روش استفاده از آنها بیشتر آشنا شویم. از آن جایی که پیادهسازی forwardRef در تایپ اسکریپت دارای محدودیت میباشد، به عنوان راه حل پیشنهاد شده است که آن را به یک تابع جدید و با یک تایپ دیگر مجددا تعریف نماییم و به این صورت محدودیت استفاده از آن را برطرف کنیم.
۵۰ درصد تخفیف ویژه پاییز فرانت کست تا پایان هفته
کد تخفیف: atm