实现一些简单的react hooks........
在钩子函数中不要使用if判断,避免钩子错乱
建立数组映射,建立多组钩子
初始化数组和索引,全局使用
let hookIndex = 0 let hookState = []
1.useState
function useState(initialState) { // 将当前的状态保存到数组 0:0,按照索引位置存储 hookState[hookIndex] = hookState[hookIndex] || initialState // 初始存储 // 这里对hookIndex进行保存,保证setState时拿到的是自己的索引 let currentIndex = hookIndex function setState(newState) { // 利用闭包保持对自己的state进行更新 hookState[currentIndex] = newState // 页面重新渲染 render() } return [hookState[hookIndex++], setState] // hookIndex++目的是让下一次存储位置+1 }
2.useCallback
useCallback和useMemo是性能优化的手段,可以通过 useCallback,useMemo对传递给子组件的数据和函数进行包裹比较,再将子组件通过React.memo包裹,当依赖项没有变化时,让子组件不用随着父组件进行每次的更新
useCallback
const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );
使用如下:
function App() { const [name, setName] = useState('jiang'); const [age, setAge] = useState(13); const data = useMemo(() => ({ age }), [age]); // 这里看一下age如果没有变化 则使用第一次函数返回的结果 // 否则每次返回新的引用地址,每次都会更新 const addClick = useCallback(() => setAge(age + 1), [age]) return ( <div> {name} <input type="text" value={name} onChange={e => setName(e.target.value)}></input> <Child data={data} onButtonClick={addClick}></Child> </div> ) } function Child({ data, onButtonClick }) { console.log('child click') return <div>{data.age} <button onClick={onButtonClick} >修改年龄</button></div> } Child = React.memo(Child); // 要比较两个属性 前后如果一致就不会更新了 shouldComponentUpdate
实现useCallback如下:
useCallback(callback, dependencies) { // 如果已经缓存过对象 if (hookState[hookIndex]) { let [lastCallback, lastDependencies] = hookState[hookIndex] // 读取缓存的hookState中的useCallback // 遍历dependencies 和lastDependencies,如果没有变化则返回原来的对象 // 如果有变化,返回最新的dependenies const isSame = dependencies.every((item, index) => item === lastDependencies[index]) // 遍历判断 if (isSame) { // 如果没有变化,直接返回原来的 hookIndex++ return lastCallback } else { // 如果有变化,进行更新并返回新结果 hookState[hookIndex++] = [callback, dependencies] return callback } } else { // 没有缓存过对象 hookState[hookIndex++] = [callback, dependencies] // 将第一次的结果缓存起来 return callback } }
3.useMemo
useMemo与useCallback类似,useMemo包裹的是复杂的数据型
useCallback(fn, deps)
相当于 useMemo(() => fn, deps)
记住,传入 useMemo
的函数会在渲染期间执行。请不要在这个函数内部执行不应该在渲染期间内执行的操作,诸如副作用这类的操作属于 useEffect
的适用范畴,而不是 useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
useMemo的实现和useCallback原理差不多
只不过useMemo缓存的是fn的调用值fn()
useMemo(factory, dependencies) { // 如果已经缓存过对象 if (hookState[hookIndex]) { let [lastMemo, lastDependencies] = hookState[hookIndex] // 读取缓存的hookState中的useCallback // 遍历dependencies 和lastDependencies,如果没有变化则返回原来的对象 // 如果有变化,返回最新的dependenies const isSame = dependencies.every((item, index) => item === lastDependencies[index]) // 遍历判断 if (isSame) { // 如果没有变化,直接返回原来的 hookIndex++ return lastMemo } else { // 如果有变化,进行更新并返回新结果 hookState[hookIndex++] = [factory(), dependencies] return factory() } } else { // 没有缓存过对象 hookState[hookIndex++] = [factory(), dependencies] // 将第一次的结果缓存起来 return factory() } }
4.useEffect
useEffect可以实现类似与 componentDidMount, componentDidUpdate, componentDidUnMount的生命周期效果
实现如下:
useEffect(callback, dependencies) { // 如果已经缓存过对象 if (hookState[hookIndex]) { // 判断依赖项是否变化 const [lastDestroy, lastDependencies] = hookState[hookIndex] // 默认每次都会重新渲染 let isSame = false if (lastDependencies) { isSame = dependencies.every((item, index) => item === lastDependencies[index]) } // 如果有依赖项并且依赖项没有变化 if (isSame) { // 不做任何操作,将hookIndex++, 以便下一个hooks调用 hookIndex++ } else { // 如果有销毁函数return 则执行 lastDestroy && lastDestroy() // 如果没有依赖项或者依赖项发生变化,则进行更新 hookIndex[hookIndex++] = [callback(), dependencies] } } else { // 如果没有缓存过对象,则对其进行缓存 hookIndex[hookIndex++] = [callback(), dependencies] // 因为只是对callback进行执行函数,所以不需要返回值 // 或许需要写成下面的方式(setTimeout)-因为useEffect是在渲染之后调用,如果直接调用的话则是在渲染期间就执行了 // let arr = [, dependencies] // setTimeout(() => { // arr[0] = callback(); // }) // hookStates[hookIndex++] = arr } }
5.useLayoutEffect
我的理解是和useEffect差不多
但是useEffect 内部执行的是宏任务,而useLayoutEffect内部实现的是微任务
所以在实现动画效果时会有差别, useLayoutEffect会优先执行,减少动态的效果
6. useRef
function useRef(initialState) { // 保存一个current属性 hookStates[hookIndex] = hookStates[hookIndex] || { current: initialState }; return hookStates[hookIndex++] }
等看完react源码之后再来补充一下
标签:++,hooks,useCallback,react,useMemo,dependencies,hookState,手写,hookIndex From: https://www.cnblogs.com/best-mll/p/16611296.html