比如 react-redux 中的 connect 组件,接受一个组件,返回一个新的组件,给新的组件添加新的组件
缺点 : 容易形成嵌套地狱
现在主要用hook 使用状态
组件内部state,适合在本组件使用。有点灵活,缺点难以实现组件共享
函数组件 用useState useReducer
类组件 this.state 修改this.setState
组件外的state ,用状态管理库。redux dva umi
修改状态,使用subscribe订阅刷新页面,后有了hook,usedDispatch之类的hook
将订阅页面更新放到了页面里面
redux 中的subscribe返回值是取消订阅 (想想源码的return
复用的前提必须满足三个条件:同一层级下,同一类型,同一个key值,所以我们尽量保证这三者的稳定性
常见错误比如key=Match.random() 做key值 这样就会每次卸载旧的组件 生成新的组件
不规范写法 用key = index 但是组件如果发生拖拽啥的就寄了
在类组件中 通过shouldcomponentupdate生命周期判断
this.props.item !==nextPpropsitem 就return false 不更新
类组件中 使用purcomponent 内置了通过shouldcomponentupdate,通过判断props是否有变化
函数组件中 使用memo 其实HOC高阶组件,memo会检查属性是否发生变化,来选择是否重新渲染,源码会进行浅比较会直接进入bailout,也可以自定义函数,放进去一个callback函数
const a = memo(function Home() {
return(<>
home page
</>)
},(pre,current)=>{
return pre.item !== current.item
})
useMemo 把返回值返回到filber节点上
export default const a =({item}) =>{ //这里child组件并不依赖item的变化重新更新
return useMemo (() => {
<div>
{item}
<Child/>
</div>
})
}
useCallback 可以缓存函数
使用useCallback(fn,deep) == useMemp (() => fn,deep)
context value 只要发生变化 消费这个组件的后代consumer都要更新 所以要尽量的精简实用 比如项目里页面初次加载就把所有的dymanic数据和static数据全请求出来
比如拆分不想管的context 比如俩个不想关联的context 拆开 这样就不用修改某个的时候 全部渲染了
就是自己封装的hook 最经典的就是alibaba/ahooks 里面的一些定时器,forceupdate
之前函数组件不能保存状态是因为当状态改变的时候 页面就要重新渲染 这样定义在函数里面的变量就会重新生成复制,肯定不行,如果定义在函数外面全局污染 直接傻杯
所以hook出现后 封装了useState 和 useReducer方法 把state状态保存到了filber上
简单的用state 复杂想复用的用useReducer
注意 state 不改变页面不刷新 reducer 刷新
因为如果肯定要有一个状态 ,和改变状态的俩个变量,如果是对象解构的话就名字定死了,数组就可以随便起名字了
首先回顾一下什么是副作用,改变dom ,添加订阅,设置定时器,记录日志等等
简单的例子 – 比如说一个ajax 就要写到effect 里面 直接写到函数体里 每次都执行 而且可能阻塞后面js的运行
怎么选?
大部分场景都用useEffect ,那useEffect 和 useLayoutEffect有什么区别
通过掘金老哥和自己查的资料这么理解:
首先uselayoutEffect是同步,useEffect是异步
useEffect是组件渲染在页面渲染后延迟执行,而usLayoutEffect是在所有的dom变更之后执行
掘金老哥的例子
使用useEffect 这里会闪烁 ,setcount 会先让count值变为0,然后useEffect会让count更改为一个随机数,因为很快,所以会闪烁
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
if (count === 0) {
const randomNum = 10 + Math.random()*200
setCount(10 + Math.random()*200);
}
}, [count]);
return (
<div onClick={() => setCount(0)}>{count}</div>
);
}
使用useLayoutEffect不回闪烁,layout要等里面的签名函数全部执行完后,才更新刷新渲染,这个时候时候count的值已经是随机数了
用户感知不到count是0这一个变化,也就是说这里layout和setcount是同时执行的,而上面的uerEffect是setCount已经重新渲染页面了,然后才执行签名函数里面的set为随机数
function App() {
const [count, setCount] = useState(0);
useLayoutEffect(() => {
if (count === 0) {
const randomNum = 10 + Math.random()*200
setCount(10 + Math.random()*200);
}
}, [count]);
return (
<div onClick={() => setCount(0)}>{count}</div>
);
}
再总结一下,就是effect会先渲染页面,然后执行里面的签名函数,而useLayoutEffect不会等页面渲染完才执行,同时执行,也就是所谓的同步异步,然后可以举这个例子,setcount 外面执行一次,副作用函数里面执行一次
再比如 ract-router-dom v6里面 就使用用useLayoutEffect 因为要去监听,history 。如果用effect的话,就是该更新了(setstate了),但是还没监听呢
记住这个柯利化
function addware(...arg) {
return (params) => (arg1) => {
console.log('ageOutSide',arg)
console.log('inside1', arg1)
console.log('inside2', params)
}
}
const useEnhancer = (enhancer) => {
return enhancer('params1')('params2')
}
addware('addwareparams')
useEnhancer(addware('addwareparams'))