Skip to content

Latest commit

 

History

History
157 lines (126 loc) · 5.63 KB

somecase.md

File metadata and controls

157 lines (126 loc) · 5.63 KB

一些有关 React 的知识点

setSate具有确定的顺序

来源 React 是否保持 state 更新的顺序?

无论是同一个组件,还是不同的组件,setSatte都具有确定的顺序。 状态始终是按照特定的顺序更新的。无论你是否看到介于两个状态之间的一个中间状态,无论你是否在批处理内。

React 事件处理程序中(可以理解为由 React引发的事件处理,例如 onClick onChange),不论 setState() 调用了多少次,也不论 setState() 被多少个组件调用,它们在事件结束时只会生成一次重新渲染,也就是在事件结束时,所有的 setState调用都会被合并到一起。

更新总是按照它们发生的顺序进行浅合并(shallowly merge)。

但是,截至目前,也就是 React 16 和更早版本中,React 事件处理程序 之外还没有默认的批处理

例如,下述的 handleClick函数中的代码,就是在 React 事件处理程序之内:

<button onClick={this.handleClick}>click</button>

handleClick = () => {
  this.setState({ a: 1 }); // 不立即重新渲染
  this.setState({ b: 2 }); // 不立即重新渲染
  console.log('be clicked');
}
// 当所有的 React 事件处理程序 全部结束后,会一次性改变状态,组件重新渲染一次

下述的 getData函数中的代码,则是在 React 事件处理程序之外:

getData() {
  promise.then(data => {
    this.setState({ a: data }); // 使用 { a: data }重新渲染一次
    this.setState({ b: 2 }); // 使用 { b: 2 }重新渲染一次
  });
}

React未来的版本(或许是从 React 17开始),可能会默认支持批量更新所有的更新,在此之前,React也提供了一个 API用于强制批量处理:

promise.then(() => {
  // 强制批量处理
  ReactDOM.unstable_batchedUpdates(() => {
    this.setState({ a: true }); // 不立即重新渲染
    this.setState({ b: false }); // 不立即重新渲染
  });
  // 当我们退出 unstable_batchedUpdates函数后,重新渲染一次
});

不要在 componentWillMount中获取数据

componentWillMount里发起AJAX,不管多快得到结果也赶不上首次render,而且 componentWillMount可能会被调用多次,所以类似的 IO操作最好放到 componentDidMount

react-router 4.x:切换路由后,页面仍然停留在上一个页面的位置

更多 react-router使用技巧可见 React Router 4.x 开发,这些雷区我们都帮你踩过了

由 A 页面跳转到 B 页面,B 页面停留在 A 页面的位置,没有返回到顶部。

3.x以及早期版本中,可以使用滚动恢复的开箱即用功能,但是在 4.x中路由切换并不会回复滚动位置。

解决方法:使用 withRouter

withRouter(MyComponent) withRouter 可以访问历史对象的属性和最近的 <Route> 匹配项,当路由的属性值 { match, location, history } 改变时, withRouter 都会重新渲染。该组件可以携带组件的路由信息,避免组件之间一层层传递。

所以可以利用上述特点,使用 withRouter 封装出一个 ScrollToTop 组件。 这里就用到了 withRouter 携带路由信息的特性,通过对比propslocation 的变化,实现页面的滚动。

import React, { Component } from 'react';
import { Route, withRouter } from 'react-router-dom';
class ScrollToTop extends Component {
  componentDidUpdate(prevProps) {
    if (this.props.location !== prevProps.location) {
      window.scrollTo(0, 0);
    }
  }
  render() {
    return this.props.children;
  }
}

export default withRouter(ScrollToTop);

在定义路由出引用该组件,例如:

ReactDOM.render((
  <BrowserRouter>
    <ScrollToTop>
      <div className="container">
        <Route path={routePaths.INDEX} exact component={Index} />
        <Route path={routePaths.CARD} component={Card} />
      </div>
    </ScrollToTop>
  </BrowserRouter>
  ),
  document.getElementById('app')
);

指一种在 React 组件之间使用一个值为函数的 propReact 组件间共享代码的简单技术,主要用于简化 react 组件的复用方式

class DataProvider extends React.Component {
  constructor(props) {
    super(props);
    this.state = { target: 'Zac' };
  }

  render() {
    return (
      <div>
        {this.props.render(this.state)}
      </div>
    )
  }
}

// 使用 render Props
<DataProvider render={data => (
  <Cat target={data.target} />
)} />

虽然这个模式叫 Render Props,但不是说非用一个叫 renderprops不可,习惯上大家更常写成下面这种:

<DataProvider>
  {data => (
    <Cat target={data.target} />
  )}
</DataProvider>

$$typeof

React 在解析 jsxvdom的时候,会在 vdom的对象中额外添加一个 $$typeof的属性:

const element = {
  // This tag allows us to uniquely identify this as a React Element
  $$typeof: REACT_ELEMENT_TYPE,

  // Built-in properties that belong on the element
  type: type,
  key: key,
  ref: ref,
  props: props,

  // Record the component responsible for creating this element.
  _owner: owner,
};

$$typeof 是一个 Symbol类型的值,主要用于防止 XSS攻击,因为此类型的值无法序列化,所以如果对