REACT
setState
- 更新数据是一个异步操作
- 不能在 render 中触发 setState
- 只在合成事件和钩子函数中是异步的,原生事件和 settimerout 中是同步的
- 在 setState 函数中,会根据一个变量 isBatchingUpdates 判断是直接更新 this.state 还是放到队列中延时更新,默认是 false,但当 react 调用事件处理函数之前会先调用 batchedUpdates 将 isBatchingUpdates 修改为 true,这样 setState 就不会同步更新 this.state
React 的 hooks
useState:让 function 组件可以自己维护 state
userCallback:避免组件重复渲染,提高性能
userReducer:function 组件需要维护复杂数据的时候使用(函数,初始值)
userEffect
- 第一个参数是一个回调函数
- 第二个参数是一个数组,数组中放的是依赖
- 只有当数组中的依赖改变的时候才会触发这个回调函数
- 第二个参数可以不穿,不传的时候相当于类组件的 didmount 和 didupdate 的合体
- 第二个参数如果是一个空数组。则类似于我们类组件的 didmount
- return 的函数可以用来清除当前回调函数的副作用,类似 componentwillUnmount
useMemo
- shouldcomponentupdate 类似作用,在渲染中避免重复渲染
hooks会有一些写法规范,是出于什么原因?
- 不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 useState 和 useEffect 调用之间保持 hook 状态的正确。 www.jianshu.com/p/769014106…
为什么使用 function 组件
- class 组件冗余,每次都会创建一个实例
- 学习成本大,this 指向有困难
react 的生命周期
- 生命周期是一个抽象的概念(挂载、更新,卸载)
- 挂载阶段:指组件从初始化到完成加载的过程
- 更新阶段:外部 props 传入或者 state 发生变化时的阶段
- 卸载阶段:清理工作,解除定时器和事件绑定
- constructor:类通用的构造函数,常用于初始化
- constructor 中并不推荐区处理初始化以外的逻辑
- constructor 并不属于 React 的生命周期,只是 Class 的初始化函数
- 代码更加简洁
- getDerivedStateFromProps(props, state)
- 可以把 props 转到 state 中
- 把返回的对象合并到 state 中
- 使组件在 props 变化时更新 state
- 触发时机
- props 被传入
- State 发生变化时
- forceUpdate 被调用时
- UNSAFE_componentWillMount()
- 用于组件加载前做某些操作
- 对比成 vue 的 beforeMount 但是已经被废弃
- 由于异步渲染机制,该方法可能会被多次调用
- 同构渲染时在此方法请求数据,会在服务端和客户端触发两次
- 不能和 1 同时出现
- render()
- 返回 jsx 结构,用于描述具体的渲染内容
- render 并没有真正的渲染组件
- 不能 setstate 和绑定事件
- componentDidMount()
- 主要用于组件加载完成时做某些操作
- 对比与 vue 的 mounted
- ajax 请求的发送都在这个钩子中进行
- 接着 render 之后调用
- 在真实 DOM 绘制完成之后调用
- UNSAFE_componentWillReceiveProps
- 可被 getDerivedStateFromProps 替代
- shouldComponentUpdate(nextProps,nextState)
- 返回一个 true,当前组件更新
- 返回一个 false,当前组件不更新
- UNSAFE_componentWillUpdate()
- 被废除.
- getSnapshotBeforeUpdate
- 配合 react 新的异步渲染机制,在 dom 更新发生前被调用,返回值作为 componentDidUpdate 的第三个参数
- componentDidUpdate()
- 类比于 vue 的 updated
- componentWillUnmount()
- 类比于 vue 的 beforeDestory()
- 一般用来销毁定时器或者某些事件
如何避免生命周期中的坑
- 重新渲染的三种情况
- 函数组件任何情况下都会重新渲染,优化手段 React.memo
- React.Component
- State 发生变化时
- 当父组件的 props 传入时,无论 props 有没有变化,只要传入就会引发重新渲染
- React.PureComponent
- 仅在 props 和 state 进行浅比较后,确认有变更时才会触发重新渲染
- 避免生命周期中的坑需要做好两件事:
- 不在恰当的时候调用了不该调用的代码;
- 在需要调用时,不要忘了调用。
- 主要有 7 种情况容易造成生命周期的坑。
- getDerivedStateFromProps 容易编写反模式代码,使受控组件与非受控组件区分模糊。
- componentWillMount 在 React 中已被标记弃用,不推荐使用,主要原因是新的异步渲染架构会导致它被多次调用。所以网络请求及事件绑定代码应移至 componentDidMount 中。
- componentWillReceiveProps 同样被标记弃用,被 getDerivedStateFromProps 所取代,主要原因是性能问题。
- shouldComponentUpdate 通过返回 true 或者 false 来确定是否需要触发新的渲染。主要用于性能优化。
- componentWillUpdate 同样是由于新的异步渲染机制,而被标记废弃,不推荐使用,原先的逻辑可结合 getSnapshotBeforeUpdate 与 componentDidUpdate 改造使用。
- 如果在 componentWillUnmount 函数中忘记解除事件绑定,取消定时器等清理操作,容易引发 bug。
- 如果没有添加错误边界处理,当渲染发生异常时,用户将会看到一个无法操作的白屏,所以一定要添加。
PureComponent:
- 内部默认调用了 shouldComponentUpdate
- 如果是引用类型可能不生效,因为地址不同
React 的请求应该放在哪里,为什么?
- 对于异步请求,应该放在 componentDidMount 中去操作。从时间顺序来看,除了 componentDidMount 还可以有以下选择:
- constructor:可以放,但从设计上而言不推荐。constructor 主要用于初始化 state 与函数绑定,并不承载业务逻辑。而且随着类属性的流行,constructor 已经很少使用了。
- componentWillMount:已被标记废弃,在新的异步渲染架构下会触发多次渲染,容易引发 Bug,不利于未来 React 升级后的代码维护。
- 所以 React 的请求放在 componentDidMount 里是最好的选择。
函数组件和类组件的区别
- 作为组件而言,类组件与函数组件在使用与呈现上没有任何不同
- 类组件是基于面向对象编程的,它主打的是继承、生命周期等核心概念;而函数组件是函数式编程,主打的是 immutable、没有副作用、引用透明等特点
- 如果存在需要使用生命周期或使用继承的组件,那么主推类组件。
- 但现在由于 React Hooks 的推出,函数组件可以完全取代类组件。
- 类组件主要依靠 shouldComponentUpdate 阻断渲染来提升性能,而函数组件依靠 React.memo 缓存渲染结果来提升性能。
- 类组件更容易上手,由于 React Hooks 的推出,函数组件成了社区未来主推的方案。
说一下Redux
- 是一种数据管理模型,和 react 没有什么关系
- 想把 redux 应用到 react 中必须借助 react-redux
- state、reducer、action
- 单一数据源
- state 只读
- 使用纯函数来执行修改 reducer
Redux有哪些弊端
- getState返回返回的值和原始容器中的state用的同一个堆内存,这样会导致获取state后直接就能修改容器中的状态信息
- 向subscribe中追加方法的时候没有做去重处理
- dispatch:如果状态改变通知事件池中的方法会全部依次执行,应该做一个判断,对应的组件中用到的事件执行即可
react-redux:专门为react项目封装的redux处理库,简化redux在组件中的应用代码
- Provider:把store挂载到祖先元素的上下文忠,方便后期后台组件的调用
- connect高阶函数
- 把redux容器中存储的状态以及需要派发的行为任务都通过属性传递给当前组件
- 会自动像事件池中追加当前组件的重新渲染方法,保证状态更新,组件会重新渲染(省略了subscribe方法)
- mapStateToProps:把redux容器中的公共状态当做属性传递给当前的组件
- mapDispatchToProps:把需要派发的行为方法通过属性传递给当前的组件
- connect会默认把actionCreator对象变为mapDispatchToProps这种函数的模式
redux中间件
- applyMiddleware:应用中间件
- createrStore(reducer,applyMiddleware(...要用的中间件))
- redux-logger:在控制台输出每一次派发任务的情况
- 管控actioncreators中异步处理(2选1即可)
- redux-thunk
- reducer中将返回的对象改写返回dispatch函数,函数里面做异步处理
- 每次点击会进行两次派发
- redux-promise
- 传递给reducer的action对象中的参数必须叫做payload,返回的还是一个对象
- payload:new Promise(resolve=>{settimeout(()=>{resolve(10)},1000)})
- 每次点击也是两次派发
- redux-thunk