You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
以下是官网的一个例子,创建 Props 和 State 接口,Props 接口接受 name 和 enthusiasmLevel 参数,State 接口接受 currentEnthusiasm 参数:
import*asReactfrom"react";
export interfaceProps{name: string;enthusiasmLevel?: number;}interfaceState{
currentEnthusiasm: number;}classHelloextendsReact.Component<Props,State>{constructor(props: Props){super(props);this.state={currentEnthusiasm: props.enthusiasmLevel||1};}
onIncrement =()=>this.updateEnthusiasm(this.state.currentEnthusiasm+1);onDecrement=()=>this.updateEnthusiasm(this.state.currentEnthusiasm-1);render(){const{ name }=this.props;if(this.state.currentEnthusiasm<=0){thrownewError('You could be a little more enthusiastic. :D');}return(<divclassName="hello"><divclassName="greeting">
Hello {name+getExclamationMarks(this.state.currentEnthusiasm)}</div><buttononClick={this.onDecrement}>-</button><buttononClick={this.onIncrement}>+</button></div>);}updateEnthusiasm(currentEnthusiasm: number){this.setState({ currentEnthusiasm });}}exportdefaultHello;functiongetExclamationMarks(numChars: number){returnArray(numChars+1).join('!');}
functionTextInputWithFocusButton(){constinputEl=useRef<HTMLInputElement>(null);constonButtonClick=()=>{inputEl.current.focus();};return(<><inputref={inputEl}type="text"/><buttononClick={onButtonClick}>Focus the input</button></>);}
与 useEffect Hooks 类似,都是执行副作用操作。但是它是在所有 DOM 更新完成后触发。可以用来执行一些与布局相关的副作用,比如获取 DOM 元素宽高,窗口滚动距离等等。
useLayoutEffect(()=>{doSomething});
进行副作用操作时尽量优先选择 useEffect,以免阻止视图更新。与 DOM 无关的副作用操作请使用 useEffect。
importReact,{useRef,useState,useLayoutEffect}from'react';exportdefault()=>{constdivRef=useRef(null);const[height,setHeight]=useState(50);useLayoutEffect(()=>{// DOM 更新完成后打印出 div 的高度console.log('useLayoutEffect: ',divRef.current.clientHeight);})return<><divref={divRef}style={{background: 'red',height: height}}>Hello</div><buttononClick={()=>setHeight(height+50)}>改变 div 高度</button></>}
useDebugValue with TypeScript
useDebugValue是用于调试自定义挂钩(自定义挂钩请参考https://reactjs.org/docs/hooks-custom.html)的工具。它允许您在 React Dev Tools 中显示自定义钩子函数的标签。
引言
React v16.8 引入了 Hooks,它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。这些功能可以在应用程序中的各个组件之间使用,从而易于共享逻辑。Hook 令人兴奋并迅速被采用,React 团队甚至想象它们最终将替换类组件。
以前在 React 中,共享逻辑的方法是通过高阶组件和 props 渲染。Hooks 提供了一种更简单方便的方法来重用代码并使组件可塑形更强。
本文将展示 TypeScript 与 React 集成后的一些变化,以及如何将类型添加到 Hooks 以及你的自定义 Hooks 上。
![](https://camo.githubusercontent.com/9a47c4097e5cf2023094489c851b3802aa6ffaf9fe27fe634a8f2d973efd4a1a/68747470733a2f2f757365722d676f6c642d63646e2e786974752e696f2f323031392f31322f32312f313666323739333436356666636563373f773d33313826683d31353926663d706e6726733d34363137)
引入 Typescript 后的变化
有状态组件(ClassComponent)
API 对应为:
以下是官网的一个例子,创建 Props 和 State 接口,Props 接口接受 name 和 enthusiasmLevel 参数,State 接口接受 currentEnthusiasm 参数:
TypeScript 可以对 JSX 进行解析,充分利用其本身的静态检查功能,使用泛型进行 Props、 State 的类型定义。定义后在使用 this.state 和 this.props 时可以在编辑器中获得更好的智能提示,并且会对类型进行检查。
react 规定不能通过 this.props.xxx 和 this.state.xxx 直接进行修改,所以可以通过 readonly 将 State 和 Props 标记为不可变数据:
无状态组件(StatelessComponent)
API 对应为:
无状态组件也称为傻瓜组件,如果一个组件内部没有自身的 state,那么组件就可以称为无状态组件。在
@types/react
已经定义了一个类型type SFC<P = {}> = StatelessComponent
先看一下之前无状态组件的写法:
如果采用 ts 来编写出来的无状态组件是这样的:
事件处理
我们在进行事件注册时经常会在事件处理函数中使用 event 事件对象,例如当使用鼠标事件时我们会通过 clientX、clientY 去获取指针的坐标。
大家可以想到直接把 event 设置为 any 类型,但是这样就失去了我们对代码进行静态检查的意义。
试想下当我们注册一个
Touch
事件,然后错误的通过事件处理函数中的event
对象去获取其clientY
属性的值,在这里我们已经将 event 设置为 any 类型,导致 TypeScript 在编译时并不会提示我们错误, 当我们通过 event.clientY 访问时就有问题了,因为 Touch 事件的 event 对象并没有 clientY 这个属性。通过
interface
对 event 对象进行类型声明编写的话又十分浪费时间,幸运的是 React 的声明文件提供了 Event 对象的类型声明。API 对应为:
简单的示例:
常用 Event 事件对象类型:
简单的示例:
React 元素
API 对应为:
简单的示例:
React Node
API 对应为:
表示任何类型的 React 节点(基本上是 ReactElement + 原始 JS 类型的合集)
简单的示例:
React CSS 属性
API 对应为:
用于标识 jsx 文件中的 style 对象(通常用于
css-in-js
)简单的示例:
Hooks 登场
首先,什么是 Hooks 呢?
React 一直都提倡使用函数组件,但是有时候需要使用 state 或者其他一些功能时,只能使用类组件,因为函数组件没有实例,没有生命周期函数,只有类组件才有。
Hooks 是 React 16.8 新增的特性,它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
默认情况下,React 包含 10 个钩子。其中 3 个挂钩被视为是最常使用的“基本”或核心挂钩。还有 7 个额外的“高级”挂钩,这些挂钩最常用于边缘情况。10 个钩子如下:
useState
useEffect
useContext
useReducer
useCallback
useMemo
useRef
useImperativeHandle
useLayoutEffect
useDebugValue
useState with TypeScript
API 对应为:
useState
是一个允许我们替换类组件中的 this.state 的挂钩。我们执行该挂钩,该挂钩返回一个包含当前状态值和一个用于更新状态的函数的数组。状态更新时,它会导致组件的重新 render。下面的代码显示了一个简单的 useState 钩子:useEffect with TypeScript
API 对应为:
useEffect
是用于我们管理副作用(例如 API 调用)并在组件中使用 React 生命周期的。useEffect 将回调函数作为其参数,并且回调函数可以返回一个清除函数(cleanup)。回调将在第一次渲染(componentDidMount) 和组件更新时(componentDidUpate)内执行,清理函数将组件被销毁(componentWillUnmount)内执行。默认情况下,useEffect 将在每个渲染时被调用,但是你还可以传递一个可选的第二个参数,该参数仅允许您在 useEffect 依赖的值更改时或仅在初始渲染时执行。第二个可选参数是一个数组,仅当其中一个值更改时才会 reRender(重新渲染)。如果数组为空,useEffect 将仅在 initial render(初始渲染)时调用。
useContext with TypeScript
useContext
允许您利用React context
这样一种管理应用程序状态的全局方法,可以在任何组件内部进行访问而无需将值传递为 props。useContext 函数接受一个 Context 对象并返回当前上下文值。当提供程序更新时,此挂钩将触发使用最新上下文值的重新渲染。
useReducer with TypeScript
对于更复杂的状态,您可以选择将该 useReducer 函数用作的替代 useState。
如果您以前使用过
Redux
,则应该很熟悉。useReducer
接受 3 个参数(reducer,initialState,init)并返回当前的 state 以及与其配套的 dispatch 方法。reducer 是如下形式的函数(state, action) => newState
;initialState 是一个 JavaScript 对象;而 init 参数是一个惰性初始化函数,可以让你延迟加载初始状态。这听起来可能有点抽象,让我们看一个实际的例子:
看完例子再结合上面 useReducer 的 api 是不是立马就明白了呢?
useCallback with TypeScript
useCallback
钩子返回一个memoized
回调。这个钩子函数有两个参数:第一个参数是一个内联回调函数,第二个参数是一个数组。数组将在回调函数中引用,并按它们在数组中的存在顺序进行访问。useCallback 将返回一个记忆化的回调版本,它仅会在某个依赖项改变时才重新计算 memoized 值。当您将回调函数传递给子组件时,将使用此钩子。这将防止不必要的渲染,因为仅在值更改时才执行回调,从而可以优化组件。可以将这个挂钩视为与
shouldComponentUpdate
生命周期方法类似的概念。useMemo with TypeScript
useMemo
返回一个 memoized 值。 传递“创建”函数和依赖项数组。useMemo 只会在其中一个依赖项发生更改时重新计算 memoized 值。此优化有助于避免在每个渲染上进行昂贵的计算。看到这,你可能会觉得,
useMemo
和useCallback
的作用有点像啊,那它们之间有什么区别呢?useRef with TypeScript
useRef
挂钩允许你创建一个 ref 并且允许你访问基础 DOM 节点的属性。当你需要从元素中提取值或获取与 DOM 相关的元素信息(例如其滚动位置)时,可以使用此方法。useRef 返回一个可变的 ref 对象,其
.current
属性被初始化为传递的参数(initialValue)。返回的对象将存留在整个组件的生命周期中。useImperativeHandle with TypeScript
useImperativeHandle
可以让你在使用 ref 时,自定义暴露给父组件的实例值。useImperativeHandle 钩子函数接受 3 个参数: 一个 React ref、一个 createHandle 函数和一个用于暴露给父组件参数的可选数组。
useLayoutEffect with TypeScript
与 useEffect Hooks 类似,都是执行副作用操作。但是它是在
所有 DOM 更新完成后
触发。可以用来执行一些与布局相关的副作用,比如获取 DOM 元素宽高,窗口滚动距离等等。useDebugValue with TypeScript
useDebugValue
是用于调试自定义挂钩(自定义挂钩请参考https://reactjs.org/docs/hooks-custom.html
)的工具。它允许您在 React Dev Tools 中显示自定义钩子函数的标签。示例
我之前基于 umi+react+typescript+ant-design 构建了一个简单的中后台通用模板。
涵盖的功能如下:
里面对于在
react
中结合Hooks
使用typescript
的各种场景都有很好的实践,大家感兴趣的可以参考一下,https://github.com/easy-wheel/Umi-hooks/tree/feature_hook
,当然不要吝惜你的 star!!!最后
你可以关注我的同名公众号【前端森林】,这里我会定期发一些大前端相关的前沿文章和日常开发过程中的实战总结。当然,我也是开源社区的积极贡献者,github地址https://github.com/Cosen95,欢迎star!!!
The text was updated successfully, but these errors were encountered: