使用?TypeScript?開發(fā)?React?函數(shù)式組件
前言
在我們使用 React 開發(fā)項(xiàng)目時(shí),使用最多的應(yīng)該都是組件,組件又分為函數(shù)組件和類組件,我們可以這么定義:
定義函數(shù)組件:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}定義類組件:
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}這篇文章我會和大家介紹使用 TypeScript 定義函數(shù)式組件的 4 種方法,還有幾個(gè)使用過程中需要注意的問題。
如何使用 TypeScript 定義函數(shù)式組件
函數(shù)式組件通常接受一個(gè) props 參數(shù),返回一個(gè) JSX 元素或者 null。
當(dāng)我們需要使用 TypeScript 去定義一個(gè)函數(shù)式組件時(shí),我們有 4 種方式,4 種方式各有各的優(yōu)缺點(diǎn),看具體情況使用。
1. 使用 React.FC
由于 React 不是使用 TypeScript 開發(fā)的,使用的是社區(qū)開發(fā)的 @type/react 包提供的類型,里面有一個(gè)通用類型 FC ,允許我們?yōu)楹瘮?shù)組件添加類型。
type FCProps = { text: string };
// React.FunctionComponent 的簡寫
const FCComponent: React.FC<FCProps> = ({ text = "" }) => <div>{text}</div>;這里的 React.FC 是 React.FunctionComponent 的簡寫。
當(dāng)組件包含子元素,TypeScript 會提示警告:
type FCProps = { text: string };
const FCComponent: React.FC<FCProps> = ({ text = "" }) => <div>{text}</div>;
function App() {
return (
<div className="App">
<FCComponent text="Hello Chris1993.">
<span>children</span>
</FCComponent>
</div>
);
}提示警告內(nèi)容:
Type '{ children: string; text: string; }' is not assignable to type 'IntrinsicAttributes & FCProps'.
Property 'children' does not exist on type 'IntrinsicAttributes & FCProps'.現(xiàn)在不推薦使用這個(gè)了,具體討論可以看這兩個(gè)鏈接:
2. 使用 JSX.Element
使用 JSX.Element 類型作為函數(shù)式組件的返回值類型,當(dāng)組件的返回值不是 JSX.Element 類型時(shí),TypeScript 就會提示錯誤。
type FCProps = { text: string };
const ElementComponent = ({ text }: FCProps): JSX.Element => <div>{text}</div>;
function App() {
return (
<div className="App">
<ElementComponent text="Hello Chris1993."></ElementComponent>
</div>
);
}3. 直接定義完整類型
由于 React 組件包含子元素時(shí),會隱式傳遞一個(gè) children 屬性,導(dǎo)致定義的參數(shù)類型出錯,因此我們可以直接定義一個(gè)完整的參數(shù)接口,包含了 children 屬性的類型:
type FCProps = { text: string; children?: any };
const FCComponent: React.FC<FCProps> = ({ text = "" }) => <div>{text}</div>;
function App() {
return (
<div className="App">
<FCComponent text="Hello Chris1993.">
<span>children</span>
</FCComponent>
</div>
);
}4. 使用 React.PropsWithChildren
第 3 種方法每次都要手動寫一個(gè) children 屬性類型比較麻煩,這時(shí)候我們就可以使用 React.PropsWithChildren 類型,它本身封裝了 children 的類型聲明:
// react/index.d.ts
type PropsWithChildren<P> = P & { children?: ReactNode };因此,使用 React.PropsWithChildren 類型定義函數(shù)式組件,就不用去處理 children 的類型了:
type IProps = React.PropsWithChildren<{ text: string }>;
const PropsComponent = ({ text }: IProps) => <div>{text}</div>;
function App() {
return (
<div className="App">
<PropsComponent text="Hello Chris1993.">
<span>children</span>
</PropsComponent>
</div>
);
}使用過程需要注意的點(diǎn)
1. 函數(shù)式組件返回值不能是布爾值
當(dāng)我們在函數(shù)式組件內(nèi)使用條件語句時(shí),如果返回的是非 JSX 元素或者非 null 的值,React 將會報(bào)錯:
const ConditionComponent = ({ useRender = false }) =>
useRender ? <span>Render ConditionComponent</span> : false;// ?
function App() {
return (
<div className="App">
<ConditionComponent useRender></ConditionComponent>
{/* 'ConditionComponent' cannot be used as a JSX component.
Its return type 'false | Element' is not a valid JSX element.
Type 'boolean' is not assignable to type 'ReactElement<any, any>'.
*/}
</div>
);
}正確的處理方式,應(yīng)該是讓函數(shù)式組件返回一個(gè)有效的 JSX 元素或者 null:
const ConditionComponent = ({ useRender = false }) =>
useRender ? <span>Render ConditionComponent</span> : <span>error</span>;// ?
// or
const ConditionComponent = ({ useRender = false }) =>
useRender ? <span>Render ConditionComponent</span> : null;// ?當(dāng)然你也不能這樣寫,當(dāng)屬性 useRender 為 true 時(shí),也會出錯:
const ConditionComponent = ({ useRender = false }) =>
useRender && <span>Render ConditionComponent</span>;// ?2. 無法為組件使用 Array.fill() 填充
當(dāng)我們的組件直接返回 Array.fill() 的結(jié)果時(shí),TypeScript 會提示錯誤。
const ArrayComponent = () => Array(3).fill(<span>Chris1993</span>); // ?
function App() {
return (
<div className="App">
<ArrayComponent></ArrayComponent>
</div>
);
}提示下面內(nèi)容:
'ArrayComponent' cannot be used as a JSX component.
Its return type 'any[]' is not a valid JSX element.
Type 'any[]' is missing the following properties from type 'ReactElement<any, any>': type, props, key為了解決這個(gè)問題,我們可以定義函數(shù)的返回值類型:
const ArrayComponent = () => Array(3).fill(<span>Chris1993</span>) as any as JSX.Element; // ?
3. 支持使用泛型來創(chuàng)建組件
在使用 TypeScript 開發(fā) React 函數(shù)式組件的時(shí)候,也可以使用泛型進(jìn)行約束,聲明一個(gè)泛型組件(Generic Components),這樣可以讓我們的組件更加靈活。
可以這樣使用:
interface GenericProps<T> {
content: T;
}
const GenericComponent = <T extends unknown>(props: GenericProps<T>) => {
const { content } = props;
const component = <>{content}</>;
return <div>{component}</div>;
};
function App() {
return (
<div className="App">
{ /* Success ? */}
<GenericComponent<number> content={10} />
{ /* Error ? Type 'string' is not assignable to type 'number'. */}
<GenericComponent<number> content={"10"} />
</div>
);
}在 Generic Components 章節(jié)中介紹到更高級的使用方式:
interface Props<T> {
items: T[];
renderItem: (item: T) => React.ReactNode;
}
const List = <T extends unknown>(props: Props<T>) => {
const { items, renderItem } = props;
const [state, setState] = React.useState<T[]>([]); // You can use type T in List function scope.
return (
<div>
{items.map(renderItem)}
<button onClick={() => setState(items)}>Clone</button>
{JSON.stringify(state, null, 2)}
</div>
);
};
function App() {
return (
<div className="App">
<List<number>
items={[1, 2]} // type of 'string' inferred
renderItem={(item) => (
<li key={item}>
{/* Error: Property 'toPrecision' does not exist on type 'string'. */}
{item.toPrecision(3)}
</li>
)}
/>
</div>
);
}到此這篇關(guān)于使用 TypeScript 開發(fā) React 函數(shù)式組件的文章就介紹到這了,更多相關(guān)TypeScript 開發(fā) React內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- TypeScript?泛型重載函數(shù)的使用方式
- TypeScript防抖節(jié)流函數(shù)示例詳解
- TypeScript函數(shù)和類型斷言實(shí)例詳解
- Typescript 實(shí)現(xiàn)函數(shù)重載的方式
- Typescript 函數(shù)重載的實(shí)現(xiàn)
- TypeScript中的函數(shù)
- Typescript中函數(shù)類型及示例詳解
- TypeScript使用函數(shù)重載確定返回類型的實(shí)現(xiàn)方法
- 如何在TypeScript中使用函數(shù)
- TypeScript中的函數(shù)重載示例分析
- TypeScript中使用回調(diào)函數(shù)的實(shí)現(xiàn)
相關(guān)文章
使用base64對圖片的二進(jìn)制進(jìn)行編碼并用ajax進(jìn)行顯示
這篇文章主要介紹了使用base64對圖片的二進(jìn)制進(jìn)行編碼并用ajax進(jìn)行顯示的相關(guān)資料,需要的朋友可以參考下2017-01-01
詳解微信小程序?qū)崿F(xiàn)仿微信聊天界面(各種細(xì)節(jié)處理)
這篇文章主要介紹了詳解微信小程序?qū)崿F(xiàn)仿微信聊天界面(各種細(xì)節(jié)處理),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02
JavaScript中prompt()函數(shù)的用法實(shí)戰(zhàn)例子
JavaScript中的prompt是一個(gè)函數(shù),用于在瀏覽器中顯示一個(gè)對話框,提示用戶輸入一些信息,這篇文章主要給大家介紹了關(guān)于JavaScript中prompt()函數(shù)的用法實(shí)戰(zhàn),需要的朋友可以參考下2023-11-11
使用phantomjs進(jìn)行網(wǎng)頁抓取的實(shí)現(xiàn)代碼
這篇文章主要介紹了使用phantomjs進(jìn)行網(wǎng)頁抓取的實(shí)現(xiàn)代碼,需要的朋友可以參考下2014-09-09
bootstrap實(shí)現(xiàn)嵌套模態(tài)框的實(shí)例代碼
這篇文章主要介紹了bootstrap實(shí)現(xiàn)嵌套模態(tài)框的實(shí)例代碼,代碼簡單易懂,非常不錯,具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01

