Skip to content

React Tips

EricYang edited this page Jun 30, 2021 · 20 revisions

记录React开发时遇到的一些问题的解决方法和想法

key

  • Q:为什么要有key?

  • A:diff的时候可以直接对比key,复用一些未更新的node,提高效率。。。

  • 我遇到的场景:页面左侧是菜单,右侧是菜单对应的table,当菜单menuItem变了那么对应的tableContent也要展示出来,而tableContent变了时要保存,如果未保存就去切换菜单,那么需要给出提示,点击保存/取消之后才能切换。

  • 问题来了:右侧table单独抽成一个组件(因为别的地方也要用),然后抛出contentChanged,content等字段给左侧/全局,用于切换角色时判断table内容有无变化,而table的初始值是不一定相同的,那么我需要这个table组件自己去维护自己的状态,比如初始化的时候contentChanged=false,content=接口返回的数据/[],而这个table组件又需要接收menuItem来获取对应的数据,这时,如果不给table组件加一个key={menuItem}的话,那么我切换左侧menuItem之后,组件抛出来的content就不会被重新初始化,那么我此时去保存这个tableContent就会出现bug——明明table里是空的,而保存之后table里反而有了数据,这数据还是上一个menuItem对应的数据。而解决这个bug只需要给table组件加个key,让它跟menuItem绑定,menuItem改变时table组件会销毁重新创建,那么content自然也会跟着初始化。

How to get the previous props or state?

  • example:
// 1st.
function Counter() {
  const [count, setCount] = useState(0);
  const prevCount = usePrevious(count);
  return <h1>Now: {count}, before: {prevCount}</h1>;
}

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}
// 2nd.
const prevSearchText = useRef();

useEffect(() => {
  return (function (searchText) {
    return function () {
      prevSearchText.current = searchText;
    };
  })(props.searchText);
}, [props.searchText]);

生命周期

  • 虽说已经不太提倡用这玩意了,but还是挺有用的:组件的生命周期,指的是一个 React 组件从挂载,更新,销毁过程中会执行的生命钩子函数。
class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  componentWillMount() {}
 
  componentDidMount() {}

  componentWillUpdate(nextProps, nextState) {}
    
  componentWillReceiveProps(nextProps) {}  
  
  componentDidUpdate(prevProps, prevState) {}

  shouldComponentUpdate(nextProps, nextState) {}

  componentWillUnmount() {}
  
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}
  • constructor,顾名思义,组件的构造函数。一般会在这里进行 state 的初始化,事件的绑定等等

  • componentWillMount,是当组件在进行挂载操作前,执行的函数,一般紧跟着 constructor 函数后执行

  • componentDidMount,是当组件挂载在 dom 节点后执行。一般会在这里执行一些异步数据的拉取等动作

  • shouldComponentUpdate,返回 false 时,组件将不会进行更新,可用于渲染优化

  • componentWillReceiveProps,当组件收到新的 props 时会执行的函数,传入的参数就是 nextProps ,你可以在这里根据新的 props 来执行一些相关的操作,例如某些功能初始化等

  • componentWillUpdate,当组件在进行更新之前,会执行的函数

  • componentDidUpdate,当组件完成更新时,会执行的函数,传入两个参数是 prevProps 、prevState

  • componentWillUnmount,当组件准备销毁时执行。在这里一般可以执行一些回收的工作,例如 clearInterval(this.timer) 这种对定时器的回收操作

  • 官方16.3/16.4版本生命周期图

  • 简单易懂版

img

  • 补充&更新
  1. getDerivedStateFromProps(nextProps, prevState) 代替componentWillReceiveProps()。 老版本中的componentWillReceiveProps()方法判断前后两个 props 是否相同,如果不同再将新的 props 更新到相应的 state 上去。这样做一来会破坏 state 数据的单一数据源,导致组件状态变得不可预测,另一方面也会增加组件的重绘次数。

这两者最大的不同就是: 在 componentWillReceiveProps 中,我们一般会做以下两件事,一是根据 props 来更新 state,二是触发一些回调,如动画或页面跳转等。

在老版本的 React 中,这两件事我们都需要在 componentWillReceiveProps 中去做。 而在新版本中,官方将更新 state 与触发回调重新分配到了 getDerivedStateFromProps 与 componentDidUpdate 中,使得组件整体的更新逻辑更为清晰。而且在 getDerivedStateFromProps 中还禁止了组件去访问 this.props,强制让开发者去比较 nextProps 与 prevState 中的值,以确保当开发者用到 getDerivedStateFromProps 这个生命周期函数时,就是在根据当前的 props 来更新组件的 state,而不是去做其他一些让组件自身状态变得更加不可预测的事情。

  1. getSnapshotBeforeUpdate(prevProps, prevState) 代替componentWillUpdate。 常见的 componentWillUpdate 的用例是在组件更新前,读取当前某个 DOM 元素的状态,并在 componentDidUpdate 中进行相应的处理。 这两者的区别在于:

在 React 开启异步渲染模式后,在 render 阶段读取到的 DOM 元素状态并不总是和 commit 阶段相同,这就导致在 componentDidUpdate 中使用 componentWillUpdate 中读取到的 DOM 元素状态是不安全的,因为这时的值很有可能已经失效了。 getSnapshotBeforeUpdate 会在最终的 render 之前被调用,也就是说在 getSnapshotBeforeUpdate 中读取到的 DOM 元素状态是可以保证与 componentDidUpdate 中一致的。 此生命周期返回的任何值都将作为参数传递给componentDidUpdate()。

Clone this wiki locally