美文网首页
07-02-React 类组件

07-02-React 类组件

作者: magic_pill | 来源:发表于2021-12-12 22:44 被阅读0次

    目标

    • 掌握类组件的定义和使用;
    • 掌握 React 组件间通信的方式;
    • 掌握类组件的生命周期。

    内容

    • 在 React 中组件分为两种,类组件和函数组件。这里先学习一下类组件。

    类组件

    • 组件:对具有一定独立功能的数据与方法的封装,对外暴露接口,有利于代码功能的复用,且不用担心冲突。

    定义类组件

    • 类组件必须继承 React.Component;
    • 组件类必须有 render 方法。

    state 和 setState

    • React 的组件类似于一种状态机,UI 会随着组建的状态发生相应的变化。所以在 React 中,用户交互时,只需要进行状态的切换即可;
    • 在 React 中,状态应该是不可变值,而修改状态的唯一方法则是调用 setState 方法:setState(updater [, callback]);
      • updater:更新数据的 function/Object;
      • callback:更新成功后的回调 function;
    • 批处理:React 通常会集齐一批需要更新的组件,然后一次性更新来保证渲染的性能;
    • 浅合并:Object.assign();
    • 调用 setState 之后,会触发生命周期,重新渲染组件。
    • 同步与异步问题:
      • 默认情况下,调用 setState 为异步,并且在同一操作中,多次调用 setState,会合并处理,只更新一次;
      • 在 React 可以监控的地方:React 事件、React 组件的生命周期函数以及其它的 React 方法中,呈现异步表现,并且会对 setState进行合并操作;
      • 在异步方法中,或原生事件中,setState 呈现同步表现,不会对 setState 进行合并处理。

    事件

    • React 中的事件是一个合成事件;
      • 事件的 this 问题处理:在 constructor 中进行 this bind;或者使用箭头函数;
      • 阻止默认事件、阻止冒泡;

    组件间通信

    • 在 React.js 中,数据是从上到下流动(传递)的,也就是一个父组件可以把它的 state、props 通过 props 传递给它的子组件,但是子组件不能修改 props,React.js 是单向数据流。如果子组件需要修改父组件状态(数据),是通过回调函数方式来完成的。
    • 父级向子级通信 - props
      • 把数据添加到子组件的属性中,然后子组件从 props 属性中获取父级传递过来的数据;
    • 子集向父级通信:
      • 在父级中定义相关的数据操作方法(或其它回调),把该方法传递给子级,在子级中调用该方法给父级传递消息。

    context api —— 跨组件通信

    • 创建 context:createContext;
    • 向下传递数据:Provider(通过 value 属性);
    • 接收 context 数据:Consumer(内容为函数),或者通过 ContextType。
    • context.js 代码:
      import { createContext } from 'react';
      
      const context = createContext();
      const { Consumer, Provider } = context;
      
      export { Consumer, Provider };
      export default context;
      
    • 根节点(祖先节点)代码:
      import { PureComponent } from 'react';
      import App from './app';
      import { Provider } from './context';
      
      export default class Com02 extends PureComponent {
        state = {
          name: 'yjw',
          age: 18,
        }
      
        render() {
          return <>
            <Provider value={this.state}>
              <App />
            </Provider>
          </>
        }
      }
      
    • 中间层代码:
      import { Component } from "react";
      import Count from "./count";
      import Num from "./num";
      
      class App extends Component {
        render() { 
          return (  
            <>
              <Num />
              <Count />
            </>
          );
        }
      }
      
      export default App;
      
    • 子节点1代码:
      import { Component } from "react";
      import context from "./context";
      
      class Count extends Component {
        static contextType = context; // contextType 为固定写法
        render() { 
          return (  
            <>
              <h2>Count</h2>
              <p>name: {this.context.name}</p>
              <p>age: {this.context.age}</p>
            </>
          );
        }
      }
      
      export default Count;
      
    • 子节点2代码:
      import { Component } from "react";
      import { Consumer } from "./context";
      
      class Num extends Component {
        render() { 
          return (  
            <>
              <Consumer>
                {(context) => {
                  return (
                    <>
                      <h2>Num</h2>
                      <p>nage: {context.name}</p>
                      <p>age: {context.age}</p>
                    </>
                  )
                }}
              </Consumer>
            </>
          );
        }
      }
      
      export default Num;
      

    注:使用 context 时,shouldComponentUpdate 会失效。

    生命周期函数

    • 所谓的生命周期就是指某个事物从开始到结束的各个阶段,当然在 React.js 中指的是组件从创建到销毁的过程,React.js 在这个过程中的不同阶段调用的函数,通过这些函数,我们可以更加精确的对组件进行控制,前面我们一直在使用的 render 函数其实就是组件生命周期渲染阶段执行的函数;
    • 在 React 中,生命周期函数经历过多个版本演化:
    • 挂在阶段:
      • constructor;
      • static getDerivedStateFromProps(props, state):此时需要 return 一个值会作为当前组件的 state,如果 render 函数中需要同时从 props 和 state 中取值,不妨在这个生命周期函数中将数据全部转化到 state 中;但是通过这种方法转化后,如果某个值是 props 中的,通过 this.setState 无法修改;
      • render:生产虚拟 DOM;
      • componentDidMount:挂载完成,已经将虚拟 DOM 生产为真实 DOM,并且添加到 DOM 树中;这里多用于处理副作用:数据请求和 DOM 操作 [这里潜藏着优化点]。
    • 更新阶段:
      • static getDerivedStateFromProps(props, state){ // 这里可以直接 return props};更新阶段获取到的 props、state 为 nextProps 和 nextState,也就是说组件更新之后的 props 和 state;
      • shouldComponentUpdate(nextProps, nextState)[这里潜藏着优化点];
      • render;
      • getSnapshotBeforeUpdate(prevProps, prevState);在组件已经生成了新的虚拟 DOM,但是还没有更新真实 DOM 之前执行,用于获取更新的一些 DOM 信息,如 return document.querySelector('#box').innerHTML;单独使用会报警告,必须配合 componentDidUpdate 使用;
      • componentDidUpdate(prevProps, prevState, prevDom):这里的 prevDom 为 getSnapshotBeforeUpdate 返回的值,也多用于处理更新阶段的副作用[这里潜藏着优化点]。
    • 卸载阶段:
      • componentWillUnmount,多用于移除监听事件。

    1、记忆:挂载阶段有四个生命周期、更新阶段有五个生命周期、卸载阶段有一个生命周期,4-5-1;render 之前的生命周期函数参数都是 nextProps、nextState,render 之后的生命周期函数参数都是 prevProps、prevState。
    2、如果一次刷新,render 多次,一般有两种情况:第一、上面的三个潜藏优化点里面判断不正确,第二、hooks 里面的参数没有控制好。

    总结
    1. 类组件的生命周期函数中,最好只在 componentDidMount 和 componentDidUpdate 中调用 setState;
    2. 类组件中,如果需要进行数据请求,官方建议只能在 componentDidMount 和 componentDidUpdate 两个生命周期函数中进行数据请求;
    3. 在 componentDidUpdate 中进行数据请求或其它行为之后调用 setState 方法,一定要把条件限定好;
    4. 在 React 中使用列表渲染,一定记得加 key;key 在 React 中的取值问题:列表中唯一、更新前后同一个元素的 key 不能发生变化;key 的作用:是给元素添加了一个身份标识,用于视图更新前后,判断这是否是同一个节点;
    5. 事件:事件定义类似于 JS 中的行间事件;尽量将事件处理函数声明在实例的属性中;React 中事件是一个合成事件,所以要注意和 JS 的时间处理函数在使用时有一些区别:React 的事件处理函数中,默认 this 指向 undefined;阻止默认事件,不能使用 return false,要使用 event.preventDefault();阻止冒泡:event.stopPropagation();
    6. setState 同步异步问题(批更新batchUpdate):在批更新可以监控到的地方——异步,监控不到的地方——同步;批更新可以监控到的地方:1.React 事件、2.生命周期函数;监控不到的地方:1.DOM 事件、2.异步函数中。
    7. 在 React 中要注意一个问题,父组件更新一定会引起子组件更新。

    相关文章

      网友评论

          本文标题:07-02-React 类组件

          本文链接:https://www.haomeiwen.com/subject/mcfdfrtx.html