介绍 于react 16.8版本引入,主要功能在于让你无需建立一个类定义,便可使用
state
等react特性。
Hook 是一些可让你在==函数组件==里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用 —— 这使得你不使用 class 也能使用 React。html
逻辑代码难以在组件间复用react
render propsnpm
非class模式下,使用更多的react特性编程
没有破坏性改动数组
useState:< S >(initialState: S | (() => S))=> [S, Dispatch<SetStateAction< S >>];浏览器
useState
的组件,获取的数据并非同一个,全部 state 和反作用都是彻底隔离的。Dispatch<SetStateAction< S >>
会触发函数组件的从新渲染。useEffect:(effect: ()=>?()=>void, deps?: DependencyList)=> void;缓存
effect
返回的清洁函数(若是有)来取消反作用(好比订阅,计时器等)deps
标识effect所依赖的值数组。若为空数组[],则仅在第一次渲染后调用,并在卸载前销毁。(此时更相似componentDidMount
和 componentWillUnmount
)每次渲染后调用,==包括==第一次(React类生命周期中,componentDidMount
与 componentDidUpdate
的合集)性能优化
componentDidMount() { ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } componentWillUnmount() { ChatAPI.unsubscribeFromFriendStatus( this.props.friend.id, this.handleStatusChange ); } //假如在在组件展现在屏幕上时,friend.id变化了。此时组件没有正常取消原来的订阅逻辑,同时在取消订阅时传递了错误的好友id,可能致使一些bug
//需添加 componentDidUpdate 来解决这个问题 componentDidUpdate(prevProps) { if(prevPropsfriend.id !== this.props.friend.id){ // 取消订阅以前的 friend.id ChatAPI.unsubscribeFromFriendStatus( prevProps.friend.id, this.handleStatusChange ); // 订阅新的 friend.id ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } }
function FriendStatus(props) { // ... useEffect(() => { // ... ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; },[props.friend.id]);//仅在friend.id改变时更新
传递给 useEffect 的函数在每次渲染中都会有所不一样,这是刻意为之的。事实上这正是咱们能够在 effect 中获取最新的的值,而不用担忧其过时的缘由。每次咱们从新渲染,都会生成新的 effect,替换掉以前的。某种意义上讲,effect 更像是渲染结果的一部分 —— 每一个 effect “属于”一次特定的渲染。闭包
effect
useEffect会在每次浏览器绘制后,且下一次绘制前执行函数式编程
useMemo<T>(factory: () => T, deps: DependencyList | undefined)=> T;
deps
数组内依赖项改变时计算memoized useMemo
的函数会在渲染期间执行,可用于缓存子节点的渲染结果。const Button = React.memo((props) => { // 你的组件 });
useCallback<T extends (...args: any[]) => any>(callback: T, deps: DependencyList): T;
function MyComponent(props) { const clickCallback = React.useCallback(() => { // ... }, []); // 这里若是直接传递匿名函数,会形成每次渲染结果与上一次不一致 // 在这个例子中:MyComponent会从新渲染,但button不会 return <button onClick={clickCallback}>Click Me!</button>; }
useRef<T>(initialValue: T)=> MutableRefObject<T>;
useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)
useRef
实现了一套穿透闭包的逻辑。<div ref={myRef} />
形式传入组件,则不管该节点如何改变,React 都会将 ref 对象的 .current 属性设置为相应的 DOM 节点。function TextInputWithFocusButton() { const inputEl = useRef(null); const onButtonClick = () => { // `current` 指向已挂载到 DOM 上的文本输入元素 inputEl.current.focus(); }; return ( <> <input ref={inputEl} type="text" /> <button onClick={onButtonClick}>Focus the input</button> </> ); }
props
或者state
(prePorps
及preState
)。function Counter() { const [count, setCount] = useState(0); const prevCountRef = useRef(); useEffect(() => { prevCountRef.current = count; }); const prevCount = prevCountRef.current; return <h1>Now: {count}, before: {prevCount}</h1>; } // 或者使用自定义hook function Counter() { const [count, setCount] = useState(0); const prevCount = usePrevious(count); return <h1>Now: {count}, before: {prevCount}</h1>; } function usePrevious(value) { const ref = useRef(); useEffect(() => { ref.current = value; }); return ref.current; }
React依赖Hook调用的顺序来确保state
与useState
的对应关系。
按照官方描述,这个是 自定义Hook
自定义 Hook 是一个函数,其名称必须以“use” 开头,函数内部能够调用其余的 Hook。
import React, { useState, useEffect } from 'react'; function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); useEffect(() => { function handleStatusChange(status) { setIsOnline(status.isOnline); } ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange); }; }); return isOnline; } //第一处复用 function FriendStatus(props) { const isOnline = useFriendStatus(props.friend.id); if (isOnline === null) { return 'Loading...'; } return isOnline ? 'Online' : 'Offline'; } //第二处复用 function FriendListItem(props) { const isOnline = useFriendStatus(props.friend.id); return ( <li style={{ color: isOnline ? 'green' : 'black' }}> {props.friend.name} </li> ); }
useCallback
与useMemo
主要用于性能优化,不要过早进行性能优化。不然没法比较优化结果,极可能某个不注意的角落反而会致使性能下降。与 class 组件中的 setState
方法不一样,useState
不会自动合并更新对象。你能够用函数式的 setState
结合展开运算符来达到合并更新对象的效果。
setState(prevState => { // 也可使用 Object.assign return {...prevState, ...updatedValues}; });