内容简介:前言:一直对这个新特性非常感兴趣,终于今天有时间,花了大半天时间,把:x:用法::white_check_mark:用法:
前言:一直对这个新特性非常感兴趣,终于今天有时间,花了大半天时间,把 Hooks
的官方教程过了一遍,收获颇多,惊叹这个新特性真 TM 好用,以后开发用这个怕是要起飞了:laughing:。
状态钩子(State Hook)
const [state, setState] = useState(initialState);
-
多个
useState
时,React
依赖于每次渲染时钩子的调用顺序都是一样的(存在与每个组件关联的“存储单元”的内部列表存放JavaScript对象),从而实现钩子与状态的一一对应关系。 -
setState()
接收新的state
或者一个返回state
的函数(setCount(prevCount => prevCount - 1)}
)。 -
不同于类组件中的
setState
,useState
返回的setState
不会自动合并更新对象到旧的state
中(可以使用useReducer
)。 -
useState
可以接收一个函数返回initialState
,它只会在初次渲染时被调用。 -
当
setState
中的state
和当前的state
相等(通过Object.is
判断),将会退出更新。 - 建议将一个状态根据哪些需要值一起变化拆分为多个状态变量。
:x:用法:
const [rows, setRows] = useState(createRows(props.count)); // `createRows()`每次将会渲染将会被调用
:white_check_mark:用法:
const [rows, setRows] = useState(() => createRows(props.count)); // `createRows()`只会被调用一次
其中的 () => createRows(props.count)
会赋值给 rows
,这样就保证了只有在 rows
调用时,才会创建新的值。
作用钩子(Effect Hook)
useEffect(didUpdate);
-
相当于生命周期函数
componentDidMount
,componentDidUpdate
,componentWillUnmount
的组合。 -
可以返回一个函数(
cleanup
)用于清理。 -
每次重新渲染都将会发生
cleanup phase
:arrow_double_down:
useEffect(() => { ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; });
componentDidMount() { ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } // ====== 原因在这里 ====== componentDidUpdate(prevProps) { // Unsubscribe from the previous friend.id ChatAPI.unsubscribeFromFriendStatus( prevProps.friend.id, this.handleStatusChange ); // Subscribe to the next friend.id ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } componentWillUnmount() { ChatAPI.unsubscribeFromFriendStatus( this.props.friend.id, this.handleStatusChange ); }
// Mount with { friend: { id: 100 } } props ChatAPI.subscribeToFriendStatus(100, handleStatusChange); // Run first effect // Update with { friend: { id: 200 } } props ChatAPI.unsubscribeFromFriendStatus(100, handleStatusChange); // Clean up previous effect ChatAPI.subscribeToFriendStatus(200, handleStatusChange); // Run next effect // Update with { friend: { id: 300 } } props ChatAPI.unsubscribeFromFriendStatus(200, handleStatusChange); // Clean up previous effect ChatAPI.subscribeToFriendStatus(300, handleStatusChange); // Run next effect // Unmount ChatAPI.unsubscribeFromFriendStatus(300, handleStatusChange); // Clean up last effect
-
useEffect(() => {document.title = You clicked ${count} times;}, [count]);
,指定第二个参数(这里为[count
])变化时才发生cleanup phase
,然后执行effect
; -
上面情况,如果
useEffect
第二个参数为为[]
则表示只运行一次(componentDidMount
中执行effect
,componentWillUnmount
中进行cleanup
),永远不重新运行。 -
和
componentDidMount
/componentDidUpdate
有区别的地方在于,useEffect
中的函数会在layout
和paint
结束后才被触发。(可以使用useLayoutEffect
在下一次渲染之前(即 DOM 突变之后)同步触发) -
useEffect
虽然被推迟到浏览器绘制完成之后,但是肯定在有任何新的呈现之前启动。因为React
总是在开始更新之前刷新之前渲染的效果。
其他钩子
useContext
const context = useContext(Context);
接受一个上下文对象(由 React.createContext
创建),返回当前上下文值(由最近的上下文提供)。
附加钩子(Additional Hooks)
基本钩子的变体或用于特定边缘情况的钩子。
useReducer
const [state, dispatch] = useReducer(reducer, initialArg, init);
-
第三个参数
init
为函数,将会这样调用:init(initialArg)
,返回初始值。 -
如果返回
state
和现在的state
一样,将会在不影响子孙或者触发效果的情况下退出渲染。
useCallback
const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );
传入一个内联回调和一个输入数组,返回一个带有记忆的 函数
,只有输入数组中其中一个值变化才会更改。 useCallback(fn, inputs)
等价于 useMemo(() => fn, inputs)
。
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
传入一个创建函数和一个输入数组,返回一个带有记忆的 值 ,只有输入数组中其中一个值变化才会重新计算。
useRef
const refContainer = useRef(initialValue); // ... <input ref={refContainer} /> ...
返回一个可变的 ref
对象,可以自动将 ref
对象中的 current
属性作为初始值传递的参数,保持到组件的整个生命周期。
与在类中使用实例字段的方式类似,它 可以保留任何可变值 。
如保存前一个状态:
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>; }
useImperativeHandle
useImperativeHandle(ref, createHandle, [inputs])
自定在使用 ref 时,公开给父组件的实例值,必须和 forwardRef
一起使用。
function FancyInput(props, ref) { const inputRef = useRef(); useImperativeHandle(ref, () => ({ focus: () => { inputRef.current.focus(); } })); return <input ref={inputRef} ... />; } FancyInput = forwardRef(FancyInput);
<FancyInput ref={fancyInputRef} /> // 调用 fancyInputRef.current.focus()
useLayoutEffect
使用方法和 useLayoutEffect
一致,不过它是在 DOM 读取布局时同步触发(相当于 componentDidMount
和 componentDidUpdate
阶段)。(建议尽可能使用 useEffect
避免阻塞可视化更新)
useDebugValue
useDebugValue(value)
用于在 React DevTools
中显示自定义钩子的标签,对于自定义钩子中用于共享的部分有更大价值。
自定义显示格式:
useDebugValue(date, date => date.toDateString());
钩子(Hooks)规则
1. 只能在顶层调用,不能再循环、条件语句和嵌套函数中使用。 (原因:第1条)
正确做法:
useEffect(function persistForm() { // :+1: We're not breaking the first rule anymore if (name !== '') { localStorage.setItem('formData', name); } });
2. 只能在 React
函数组件中被调用。(可以通过自定义钩子函数解决)
可以使用 eslint-plugin-react-hooks 来强制自动执行这些规则。
自定义钩子(Hook)
-
以
use
开头,一种公约。 - 自定钩子是一种复用状态逻辑的机制(例如设置订阅和记住当前值),每次使用,内部所有状态和作用都是独立的。
-
自定义钩子每个状态独立的能力源于
useState
和useEffect
是完全独立的。
测试钩子(Hook)
function Example() { const [count, setCount] = useState(0); useEffect(() => { document.title = `You clicked ${count} times`; }); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
import React from 'react'; import ReactDOM from 'react-dom'; import { act } from 'react-dom/test-utils'; import Counter from './Counter'; let container; beforeEach(() => { container = document.createElement('div'); document.body.appendChild(container); }); afterEach(() => { document.body.removeChild(container); container = null; }); it('can render and update a counter', () => { // Test first render and effect act(() => { ReactDOM.render(<Counter />, container); }); const button = container.querySelector('button'); const label = container.querySelector('p'); expect(label.textContent).toBe('You clicked 0 times'); expect(document.title).toBe('You clicked 0 times'); // Test second render and effect act(() => { button.dispatchEvent(new MouseEvent('click', {bubbles: true})); }); expect(label.textContent).toBe('You clicked 1 times'); expect(document.title).toBe('You clicked 1 times'); });
参考
以上所述就是小编给大家介绍的《react-hooks中的一些懵逼点》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Developer's Guide to Social Programming
Mark D. Hawker / Addison-Wesley Professional / 2010-8-25 / USD 39.99
In The Developer's Guide to Social Programming, Mark Hawker shows developers how to build applications that integrate with the major social networking sites. Unlike competitive books that focus on a s......一起来看看 《Developer's Guide to Social Programming》 这本书的介绍吧!