一 hooks 之数据更新驱动
1.1 useState
const [ ①state , ②dispatch ] = useState(③initData)
① state,目的提供给 UI ,作为渲染视图的数据源。
② dispatchAction 改变 state 的函数,可以理解为推动函数组件渲染的渲染函数。
③ initData 有两种情况,第一种情况是非函数,将作为 state 初始化的值。第二种情况是函数,函数的返回值作为 useState 初始化的值。
useState 注意事项:
① 在函数组件一次执行上下文中,state 的值是固定不变的。
② 如果两次 dispatchAction 传入相同的 state 值,那么组件就不会更新。
③ 当触发 dispatchAction 在当前执行上下文中获取不到最新的 state, 只有再下一次组件 rerender 中才能获取到。
1.2 useReducer
useReducer 是 react-hooks 提供的能够在无状态组件中运行的类似redux的功能 api 。
const [ ①state , ②dispatch ] = useReducer(③reducer)
① 更新之后的 state 值。
② 派发更新的 dispatchAction 函数, 本质上和 useState 的 dispatchAction 是一样的。
③ 一个函数 reducer ,我们可以认为它就是一个 redux 中的 reducer , reducer的参数就是常规reducer里面的state和action, 返回改变后的state, 这里有一个需要注意的点就是:如果返回的 state 和之前的 state ,内存指向相同,那么组件将不会更新。
2.1 useEffect
useEffect(()=>{
return destory
},dep)
useEffect第一个参数callback,返回的destory,destory作为下一次callback执行之前调用,用于清除上一次callback产生的副作用。
第二个参数作为依赖项,是一个数组,可以有多个依赖,依赖项改变,执行上一次callback返回的destory,和执行新的effect第一个参数callback
对于useEffect执行,React处理逻辑是产用异步调用,对于每一个effect的callback,React会向setTimeout回调函数一样,放入任务队列,等到主线程任务完成,DOM更新,js执行完成,视图绘制完毕,才执行。所以effect回调函数不会阻塞浏览器绘制视图。
useEffect(()=>{
/* 请求数据 */
getUserInfo(a).then(res=>{
setUserMessage(res)
})
/* 定时器 延时器等 */
const timer = setInterval(()=>console.log(666),1000)
/* 操作dom */
console.log(div.current) /* div */
/* 事件监听等 */
window.addEventListener('resize', handleResize)
/* 此函数用于清除副作用 */
return function(){
clearInterval(timer)
window.removeEventListener('resize', handleResize)
}
/* 只有当props->a和state->number改变的时候 ,useEffect副作用函数重新执行 ,如果此时数组为空[],证明函数只有在初始化的时候执行一次相当于componentDidMount */
},[ a ,number ])
如上在useEffect中做的功能如下:
1、请求数据
2、设置定时器、延时器等。
3、操作dom,在 React Native 中可以通过 ref 获取元素位置信息等内容。
4、注册事件监听器,事件绑定,在React Native中可以注册NativeEventEmitter
5、清除定时器、延时器,解绑事件监听器等。
3.1 useContext
1、可以使用useContext,来获取父级组件传递过来的context值,这个当前值就是最近的父级组件Provider设置的value值,useContext参数一般是由createContext方式创建,也可以是父级上下文context传递的。useContext可以代替context.Consumer来获取Provider中保存的value值。
const contextValue = useContext(context)
/* 用useContext方式 /
const DemoContext = ()=> {
const value:any = useContext(Context)
/ my name is alien /
return
3.2 useRef
useRef可以用来获取元素,缓存状态,接受一个状态initState作为初始值,返回一个ref对象cur,cur上有一个current属性就是ref对象需要获取的内容
const cur = React.useRef(initState)
useRef 获取 DOM 元素
const DemoUseRef = ()=>{
const dom= useRef(null)
const handerSubmit = ()=>{
/*
const status = useRef(false)
/* 改变状态 */
const handleChangeStatus = () => {
status.current = true
}
4.1 useMemo
useMemo可以在函数组件render上下文中同步执行一个函数逻辑,这个函数的返回值可以作为一个新的状态缓存起来。
应用场景:1、在一些场景下,需要在函数组件中进行大量的逻辑计算,那么我们不期望每一次函数组件渲染都执 行这些复杂的计算逻辑,所以在useMemo的回调函数中执行这些逻辑,然后把得到的计算结果缓存起 来就可以了。
2、React在整个更新流程中,diff起到了决定性的作用,比如Context中的provider通过diff value来判 断是否更新
const cacheSomething = useMemo(create,deps)
① create:第一个参数作为一个函数,函数的返回值作为缓存值,如上demo中把children对应的element对象,缓存起来。
② deps:第二个参数作为一个数组,存放当前useMemo的依赖项,在函数组件下一次执行的时候,会对比deps依赖项里面的状态,是否有改变,如果有改变重新执行create,得到新的缓存值。
③ acheSomething:执行create的返回值。如果deps中的依赖项有改变,返回的重新执行create产生的值,否之取上一次的缓存值。
/* 通过 useMemo 得到派生出来的新状态 contextValue */
const contextValue = useMemo(() => {
return {
cacheDispatch: cacheDispatch.bind(keeper),
hasAliveStatus: hasAliveStatus.bind(keeper),
cacheDestory: (payload) => cacheDispatch.call(keeper, { type: ACTION_DESTORY, payload })
}
}, [keeper])
缓存计算结果:
function Scope(){
const style = useMemo(()=>{
let computedStyle = {}
// 经过大量的计算
return computedStyle
},[])
return
function Scope ({ children }){
const renderChild = useMemo(()=>{ children() },[ children ])
return
/* 用react.memo /
const DemoChildren = React.memo((props)=>{
/ 只有初始化的时候打印了 子组件更新 /
console.log(‘子组件更新’)
useEffect(()=>{
props.getInfo(‘子组件’)
},[])
return