07-02-React 类组件

目标

  • 掌握类组件的定义和使用;
  • 掌握 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 中要注意一个问题,父组件更新一定会引起子组件更新。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容