react知识点整理

2,576 阅读4分钟

一、基本语法

1.JSX语法

(1)setState是异步还是同步? 两者都有可能,

  • setTimeout和原生事件(事件监听)中,可以立即拿到更新结果。也就是同步
  • 在合成事件和生命周期中,不能立即拿到更新结果。也就是所谓的“异步”
  • 在合成事件和生命周期中,如果对同一个值进行多次setState,setState的批量更新策略会对其进行覆盖,取最后一次的执行
constructor () {
  super();
  this.state = {
    counter: 0
  };
}
componentDidMount() {
  // 生命周期中调用
  console.log(this.state.counter);  // 0
  this.setState({ counter: this.state.counter + 1 }); 
  this.setState({ counter: this.state.counter + 1 });
  console.log(this.state.counter);  // 0
  setTimeout(() => {
    // setTimeout中调用
    console.log(this.state.counter);  // 1
    this.setState({ counter: this.state.counter + 1 });
    console.log(this.state.counter); // 2
  }, 0);
}

2.列表渲染

map(同级元素添加唯一key值, 避免用index或者random);

key值作用:用来判断VDOM元素的唯一依据,帮助 react 识别元素被更改、添加或者删除,加快diff算法比对的速度(diff算法通过tag和key来判断,是否为相同的节点),减少渲染次数,提升性能。

3.事件

onClick,绑定事件的几种方法:

1.constructor()里指定函数this指向

class Binding extends React.Component {
  constructor() {
      this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    alert("Button Clicked")
  }

  render() {
    return (
      <input type="button" value="Click" onClick={this.handleClick} />
    )
  }
}

2.静态方法,不需要constructor()里绑定

class Binding extends React.Component {
  handleClick = () => {
    alert("Button Clicked")
  }
  render() {
    return (
      <input type="button" value="Click" onClick={this.handleClick} />
    )
  }
}

4.组件通信

单项数据流(从上而下),父组件传递数据和函数方法至子组件,子组件通过props显示数据和调用父组件方法更新数据。

5.组件生命周期

1.初始化state和props;

2.组件挂载阶段:       componentWillMount ----> render -----> componentDidMount(组件渲染完成,进行ajax请求);

3.组件更新阶段:       componentWillReceiverProps(props变化) ---> shouldComponentUpdate(props, nextProps)(返回true更新, false则不更新) ---> componentWillUpdate ---> render ----> componentDidUpdate;

4.组件卸载:componentWillUnMount(清除定时器,事件监听);

新的生命周期添加了getDerivedStateFromProps(代替componentWillReceiveProps), getSnapshotBeforeUpdate(代替componentWillUpdate

6.函数组件和类组件

  • 纯函数,输入props,输出JSX
  • 没有实例,没有生命周期,state
  • 不能扩展其他方法

7.受控组件和非受控组件

(1)受控组件:setState更新组件视图;

(2)非受控组件:必须手动操作DOM元素,setState实现不了,列如文件上传,富文本编辑器。

8.Portals

react中组件会按照既定层次进行渲染,当标签内容嵌套过多时,如果想组件渲染到父组件外,可以使用portals。 用法:

ReactDOM.createPartal{
    <div className="modal">{this.props.children}</div>,
    document.body    //  目标DOM节点     
}

应用场景

  • overflow: hidden;
  • 父组件z-index太小
  • fixed需要放在body第一层级

9.Context

Context 通过组件树提供了一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性。

父组件通过createContext创建context,provider传递value值,子组件通过指定contextType获取最外层传递的value值。

import React from "react";
const ThemeContext = React.createContext("light");

// 子组件接受context
class ThemeButton extends React.Component {
  // 指定 contextType读取当前的ThemeContext
  static contextType = ThemeContext;
  render() {
    const theme = this.context;
    return <div>Button is {theme}</div>;
  }
}

// 父组件传递context
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      theme: "light",
    };
  }

  render() {
    return (
      // provider传递context
      <ThemeContext.Provider value={this.state.theme}>
        <ThemeButton></ThemeButton>
      </ThemeContext.Provider>
    );
  }
}

10.异步组件

异步按需加载组件,主要用到了React.lazy和React.Suspense特性;

// 异步加载需要的组件
const AsyncDemo = React.lazy(() => import("./asyncDemo"));

class App extends React.Component {
  render() {
    return (
      <div>
        {/* fallbackAsyncDemo组件未加载前显示 */}
        <React.Suspense fallback={<div>loading...</div>}>
          <AsyncDemo />
        </React.Suspense>
      </div>
    );
  }
}

11.高阶组件和render Props

当项目中不同组件共用相同逻辑时,可以使用HOC或者render Props来进行公共逻辑的抽离,提高复用性。

1.高阶组件(HOC)

接受一个目标组件,返回处理后新的组件。

// 高阶组件不是一种功能,而是一种模式
const HOCFactory = (Component) => {
  class HOC extends React.Component {
    // 此处定位多个组件的公共逻辑
    render() {
      return <Component {...this.props} />;
    }
  }
  return HOC;
};

const TestComponent1 = HOCFactory(WrappedComponent1);
const TestComponent2 = HOCFactory(WrappedComponent2);

2.render Props

// 通过一个函数将class公共组件的state值作为参数传递给目标组件,并调用目标组件的render函数
class RenderFactory extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

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

const App = () => {
  <RenderFactory render={(props) => <p>{props}</p>} />;
};

12.react性能优化

(1)合理使用shouldComponentUpdate

通过比较新旧props来判断数据是否变化,如果没有变化则返回false,不更新组件,反之则重新渲染页面。在这里如果props中数据结构较为复杂,则不推荐进行深度比较,相比于更新组件,深度比较更加消耗性能。

(2)使用PureComponent(函数组件使用memo)

在shouldComponentUpdate进行进行了浅比较(Object.is),即比较了第一层的数据,适用于大部分情况

(3)bind函数位置

当我们在 React 中创建函数时,我们需要使用 bind 关键字将函数绑定到当前上下文。绑定可以在构造函数中完成,也可以在我们将函数绑定到 DOM 元素的位置上完成。

但是当我们将函数绑定到 DOM 元素的位置后,每次render的时候都会进行一次bind,这将会有一些不必要的性能损耗,而且还有可能导致子组件不必要的渲染。所以我们可以在构造函数中绑定,也可以直接写箭头函数。同理,我们尽量不写内联函数和内联属性

(4)列表渲染添加key,原因见上标题3