这篇文章主要介绍了怎么使用TypeScript开发React函数式组件的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇怎么使用TypeScript开发React函数式组件文章都会有所收获,下面我们一起来看看吧。
在我们使用 React 开发项目时,使用最多的应该都是组件,组件又分为函数组件和类组件,我们可以这么定义:
定义函数组件:
function Welcome(props) { return <h2>Hello, {props.name}</h2>; }
定义类组件:
class Welcome extends React.Component { render() { return <h2>Hello, {this.props.name}</h2>; } }
这篇文章我会和大家介绍使用 TypeScript 定义函数式组件的 4 种方法,还有几个使用过程中需要注意的问题。
函数式组件通常接受一个 props
参数,返回一个 JSX 元素或者 null
。
当我们需要使用 TypeScript 去定义一个函数式组件时,我们有 4 种方式,4 种方式各有各的优缺点,看具体情况使用。
由于 React 不是使用 TypeScript 开发的,使用的是社区开发的 @type/react
包提供的类型,里面有一个通用类型 FC
,允许我们为函数组件添加类型。
type FCProps = { text: string }; // React.FunctionComponent 的简写 const FCComponent: React.FC<FCProps> = ({ text = "" }) => <div>{text}</div>;
这里的 React.FC
是 React.FunctionComponent
的简写。
当组件包含子元素,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> ); }
提示警告内容:
Type '{ children: string; text: string; }' is not assignable to type 'IntrinsicAttributes & FCProps'. Property 'children' does not exist on type 'IntrinsicAttributes & FCProps'.
使用 JSX.Element
类型作为函数式组件的返回值类型,当组件的返回值不是 JSX.Element
类型时,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> ); }
由于 React
组件包含子元素时,会隐式传递一个 children
属性,导致定义的参数类型出错,因此我们可以直接定义一个完整的参数接口,包含了 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> ); }
第 3 种方法每次都要手动写一个 children
属性类型比较麻烦,这时候我们就可以使用 React.PropsWithChildren
类型,它本身封装了 children
的类型声明:
// react/index.d.ts type PropsWithChildren<P> = P & { children?: ReactNode };
因此,使用 React.PropsWithChildren
类型定义函数式组件,就不用去处理 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> ); }
当我们在函数式组件内使用条件语句时,如果返回的是非 JSX 元素或者非 null 的值,React 将会报错:
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> ); }
正确的处理方式,应该是让函数式组件返回一个有效的 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;// ✅
当然你也不能这样写,当属性 useRender
为 true
时,也会出错:
const ConditionComponent = ({ useRender = false }) => useRender && <span>Render ConditionComponent</span>;// ❌
当我们的组件直接返回 Array.fill()
的结果时,TypeScript 会提示错误。
const ArrayComponent = () => Array(3).fill(<span>Chris1993</span>); // ❌ function App() { return ( <div className="App"> <ArrayComponent></ArrayComponent> </div> ); }
提示下面内容:
'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
为了解决这个问题,我们可以定义函数的返回值类型:
const ArrayComponent = () => Array(3).fill(<span>Chris1993</span>) as any as JSX.Element; // ✅
在使用 TypeScript 开发 React 函数式组件的时候,也可以使用泛型进行约束,声明一个泛型组件(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 章节中介绍到更高级的使用方式:
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> ); }
关于“怎么使用TypeScript开发React函数式组件”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“怎么使用TypeScript开发React函数式组件”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。