1. 首页
  2. typescript深入探索

3分钟掌握react hook 在typescript中的姿势

hook结合typescript可以说是很香了。本文主要介绍hook结合typescript 如何使用,享受ts带给我们的编辑器提示和类型约束

useState

useState如果初始值不是null/undefined的话,是具备类型推导能力的,根据传入的初始值推断出类型;初始值是 null/undefined的话则需要传递类型定义才能进行约束。一般情况下,还是推荐传入类型(通过useState的第一个泛型参数)。


// 这里ts可以推断 value的类型并且能对setValue函数调用进行约束 const [value, setValue] = useState(0); interface MyObject { foo: string; bar?: number; } // 这里需要传递MyObject才能约束 value, setValue // 一般情况下推荐传入类型 const [value, setValue] = useState<MyObject>(null);

useContext

useContext一般根据传入的Context的值就可以推断出返回值。不需要显示传递类型


type Theme = 'light' | 'dark'; // 我们在createContext就传了类型了 const ThemeContext = createContext<Theme>('dark'); const App = () => ( <ThemeContext.Provider value="dark"> <MyComponent /> </ThemeContext.Provider> ) const MyComponent = () => { // useContext根据ThemeContext推断出类型,这里不需要显示传 const theme = useContext(ThemeContext); return <div>The theme is {theme}</div>;

useEffect useLayoutEffect

没有返回值,无需传递类型

useCallback useMemo

useMemo无需传递类型,根据函数的返回值就能推断出类型

useCallback无需传递类型,根据函数的返回值就能推断出类型。但是注意函数的入参需要定义类型,不然就是推断为any了!


const value = 10; // 推断出result是number类型 const result = useMemo(() => value * 2, [value]); const multiplier = 2; // 推断出 (value: number) => number // 注意函数入参value需要定义类型 const multiply = useCallback((value: number) => value * multiplier, [multiplier]);

useRef

useRef传非空初始值的时候可以推断类型,同样也可以通过传入第一个泛型参数来定义类型,约束ref.current的类型。


const MyInput = () => { // 这里约束inputRef是一个html元素 const inputRef = useRef<HTMLInputElement>(null); return <input ref={inputRef} /> }

// 自动推断出 myNumberRef.current 是number类型 const myNumberRef = useRef(0); myNumberRef.current += 1;

useReducer

只需要对传入useReducer的reducer函数的入参stateaction进行类型约束就能够推断出来


interface State { value: number; } type Action = | { type: 'increment' } | { type: 'decrement' } | { type: 'incrementAmount'; amount: number }; const counterReducer = (state: State, action: Action) => { switch (action.type) { case 'increment': return { value: state.value + 1 }; case 'decrement': return { value: state.value - 1 }; case 'incrementAmount': return { value: state.value + action.amount }; default: throw new Error(); } }; // 这里可以推断出state为State类型 const [state, dispatch] = useReducer(counterReducer, { value: 0 }); //能够约束传入dispatch的参数,符合Action类型 dispatch({ type: 'increment' }); dispatch({ type: 'decrement' }); dispatch({ type: 'incrementAmount', amount: 10 }); // TypeScript compilation error dispatch({ type: 'invalidActionType' });

useImperativeHandle

useImperativeHandle一般比较少用,一般用来选择函数组件对外暴露ref属性被调用,需要配合forwardRef使用。

如下例子。需要定义对外暴露的接口MyInputHandles,函数组件使用React.RefForwardingComponent对外暴露的接口调用作为泛型参数。然后就会得到约束了


// MyInputHandles 需要给父组件的useRef作为类型使用 和 RefForwardingComponent作为泛型参数传入约束 export interface MyInputHandles { focus(): void; } // 使用RefForwardingComponent 类型进行定义组件,第一个泛型参数是对外暴露的handle,第二个是Props const MyInput: RefForwardingComponent<MyInputHandles, MyInputProps> = ( props, ref ) => { const inputRef = useRef<HTMLInputElement>(null); useImperativeHandle(ref, () => ({ // 这里的返回会自动使用MyInputHandles进行类型约束 focus: () => { if (inputRef.current) { inputRef.current.focus(); } }, })); return <input {...props} ref={inputRef} />; }; // 函数组件必须使用forwardRef才能让外部组件使用该组件的ref export default forwardRef(MyInput);

// 父组件 const Autofocus = () => { // 能够约束 myInputRef.current的类型 const myInputRef = useRef<MyInputHandles>(null); useEffect(() => { if (myInputRef.current) { myInputRef.current.focus(); } }); return <MyInput ref={myInputRef} /> }

参考:

React Hooks in TypeScript

作者:flytam
链接:https://juejin.im/post/5dee3feff265da33a55f93d3

看完两件小事

如果你觉得这篇文章对你挺有启发,我想请你帮我两个小忙:

  1. 关注我们的 GitHub 博客,让我们成为长期关系
  2. 把这篇文章分享给你的朋友 / 交流群,让更多的人看到,一起进步,一起成长!
  3. 关注公众号 「画漫画的程序员」,公众号后台回复「资源」 免费领取我精心整理的前端进阶资源教程

JS中文网是中国领先的新一代开发者社区和专业的技术媒体,一个帮助开发者成长的社区,目前已经覆盖和服务了超过 300 万开发者,你每天都可以在这里找到技术世界的头条内容。欢迎热爱技术的你一起加入交流与学习,JS中文网的使命是帮助开发者用代码改变世界

本文著作权归作者所有,如若转载,请注明出处

转载请注明:文章转载自「 Js中文网 · 前端进阶资源教程 」https://www.javascriptc.com

标题:3分钟掌握react hook 在typescript中的姿势

链接:https://www.javascriptc.com/3824.html

« JavaScript 进阶之高阶函数篇
Code Review 是一场苦涩但有意思的修行»
Flutter 中文教程资源

相关推荐

QR code