React02:组件与通讯

state 和 setState

不使用setState修改state虽然会修改数据,但是并不会重新渲染视图

 setState(updater, [callback])
  • updater: 更新数据 function/object

    • obj中存储的是要修改的状态,setState本身会帮助我门合并状态

      this.setState({
        name: "修改的名字"
      })
      
    • 使用function时,setState会执行该函数,返回值必须是一个对象,对象中存储要修改的状态

      this.setState(function() {
        return {
          name: "修改name"
        }
      })
      
  • callback: 更新成功后的回调 FUNCTION

  • 异步:react通常会集齐一批需要更新的组件,然后一次性更新来保证渲染的性能

  • 浅合并 Objecr.assign()

  • 调用 setState 之后,会触发生命周期,调用render() 方法重新渲染组件

setState 的异步优化

在使用setState时,要注意是异步方法,所以在setState之后获取state还是修改之前的内容

      <button onClick={() => {
        this.setState({
          age: ++age
        });
        console.log(this.state)
      }}>+1</button>

在这里插入图片描述
优化操作:
多次setState的时候并不是直接调用render,而是把操作存入队列,在没有新的修改之后再执行,这样极大优化了频繁操作时的性能

组件间通信

在 React.js 中,数据是从上自下流动(传递)的,也就是一个父组件可以把它的 state / props 通过 props 传递给它的子组件

但是子组件不能修改 props - React.js 是单向数据流,如果子组件需要修改父组件状态(数据),是通过回调函数方式来完成的。

父级向子级通信

把数据添加子组件的属性中,然后子组件中从props属性中,获取父级传递过来的数据

import React, { Component } from 'react';
import Children from "./Children"

class App extends Component {
  state = {
    name: "lc",
  };
  render() {
    let { name } = this.state;
    return <div>
      <Children name={name}/>

    </div>;
  }
}

export default App;
import React, { Component, Fragment } from 'react';
class Children extends Component {
    state = {
        age: 6
    };
    render() {
        let { age } = this.state;
        let { name } = this.props;
        return <Fragment>
            <p>{name}</p>
			// ...
        </Fragment>;
    }
}

export default Children;

子级向父级通信

在父级中定义相关的数据操作方法(或其他回调), 把该方法传递给子级,在子级中调用该方法父级传递消息

父级定义一个方法并传递给子组件

  editName = (newName) => {
    this.setState({
      name: newName
    });
  };
  render() {
    let { name } = this.state;
    return <Children name={name} editName={this.editName} />;
  }

子级接收方法并使用

import React, { Component, Fragment } from 'react';
class Children extends Component {
    state = {
        age: 6
    };
    render() {
        let { age } = this.state;
        let { name, editName } = this.props;
        console.log(this.props);

        return <Fragment>
            <p>{name}</p>
            <button onClick={() => {
                editName("新的名字");
            }}>修改名字</button>
        </Fragment>;
    }
}
export default Children;

跨组件通信 context

注意在使用不熟练时,最好不要再项目中使用 context,context一般给第三方库使用
方法引入

React.createContext(defaultValue);

两个组件

const { Consumer, Provider } = createContext(defaultValue)
  • Provider 负责向子孙级组件传递信息
    • value 是要传递的数据
  • Context 负责接收父级组件的信息

创建context文件

import { createContext } from 'react';

const context = createContext();
const { Provider, Consumer } = context;

export default context;
export { Provider, Consumer };

父级使用Provider组件
Provider组件包裹子组件使用value属性传递数据

import React, { Component } from 'react';
import Children from "./Children";
import { Provider } from "./Context";

class App extends Component {
  state = {
    name: "lc",
  };
  editName = (newName) => {
    this.setState({
      name: newName
    });
  };
  render() {
    let { name } = this.state;
    return <Provider value={{
      name,
      editName: this.editName
    }}>

      <Children />;
    </Provider>;
  }
}

export default App;

子组件通过Consumer组件接收数据

import React, { Component, Fragment } from 'react';
import { Consumer } from "./Context";
class Children extends Component {
    render() {
        return <Consumer>
            {
                (context) => {
                    console.log(context);
                    let { name, editName } = context;
                    return <Fragment>
                        <p>{name}</p>
                        <button onClick={() => {
                            editName("新的名字");
                        }}>修改名字</button>
                    </Fragment>;
                }
            }
        </Consumer>;

    }
}

export default Children;

另一种写法

import React, { Component, Fragment } from 'react';
import context from "./context";
class Children extends Component {
    render() {
        console.log(this);
        let { name, editName } = this.context;
        return <Fragment>
            <p>{name}</p>
            <button onClick={() => {
                editName("新的名字");
            }}>修改名字</button>
        </Fragment>;
    }

}
Children.contextType = context;
export default Children;

或者使用es6 的静态属性

import React, { Component, Fragment } from 'react';
import context from "./context";
class Children extends Component {
    static contextType = context;
    render() {
        console.log(this);
        let { name, editName } = this.context;
        return <Fragment>
            <p>{name}</p>
            <button onClick={() => {
                editName("新的名字");
            }}>修改名字</button>
        </Fragment>;
    }

}
export default Children;

组件的生命周期

所谓的生命周期就是指某个事物从开始到结束的各个阶段,当然在 React.js 中指的是组件从创建到销毁的过程
React.js 在这个过程中的不同阶段调用的函数,通过这些函数,我们可以更加精确的对组件进行控制,前面我们一直在使用的 render 函数其实就是组件生命周期渲染阶段执行的函数

生命周期 演变

挂载阶段 (组件初始化)

在这里插入图片描述
组件创建–>把组件创建的虚拟DOM,生成真实DOM,添加到我们的DOM树中

  1. constructor 初始化组件
    constructor(props) {
        super(props);
        console.log("初始化组件");
    };
  1. static getDerivedStateFromProps(props) 将props和state进行关联
    static getDerivedStateFromProps(props) {
        console.log("将props和state进行关联", props);
        return {
            name: 123   // 添加内容
        };
    }

该方法返回值必须是个对象,对象属性会加到组件实例的state中
是个静态方法

  1. render 创建虚拟DOM

  2. componentDidMount – 处理副作用(请求),初始化组件完成,添加到DOM树中

    componentDidMount() {
        console.log("初始化组件完成,添加到DOM树中")
    }

请求数据都会在这里获取
在这里插入图片描述

更新阶段 – 组件重新渲染

  1. static getDerivedStateFromProps(props, state)
    static getDerivedStateFromProps(props) {
        console.log("1.组件开始更新,获取新的props,并将props绑定在state中", props);
        return {
            name: 123   // 添加内容
        };
    };
  1. shouldComponentUpdate() – 判断是否更新

        shouldComponentUpdate(nextProps, nextState) {
            console.log("2.判断组件是否需要更新,此时state和props并未改变", this.state, nextState);
            // 该方法必须有返回值,返回值是个布尔值,true则继续向下执行生命周期,完成组件更新,false则停止组件更新,后续生命周期则不被调用
            return true;
        }
    
    1. 该方法必须有返回值,返回值是个布尔值,true则继续向下执行生命周期,完成组件更新,
    2. false则停止组件更新,后续生命周期则不被调用
  2. render()

render() {
      console.log("3.重新生成虚拟DOM,准备更新组件,和老的虚拟DOM做出对比,选择更新");
  1. getSnapshotBeforeUpdate()
getSnapshotBeforeUpdate() {
    console.log("4.即将更新新的虚拟DOM,更新真实DOM,在这里可以获取更新前的DOM快照");
    let age = document.querySelector("#age");
    return age; // 此返回值会被传递给下一周期函数
}

返回值会被传递给下一周期函数

  1. componentDidUpdate() – 处理副作用(异步请求)
componentDidUpdate(prevProps, prevState, prevDom) {
    console.log("5.组件更新完成,state,props以及视图皆已更新,可通过参数获取修改前的props和state");
    console.log("第三个形参是上一周期函数传递过来的", prevDom);
    console.log(this.state);
}

在这里插入图片描述

卸载阶段

  • componentWillUnmount – 删除添加在全局的一些信息或操作

组件在挂在阶段可能会有全局方法挂载

    componentDidMount() {
        window.onresize = function() {
            let age = document.querySelector("#age");
            console.log(age.innerHTML)
        }
    }

组件卸载后此方法就会出现问题,所以一般是在卸载前先把这些方法卸载

    componentWillUnmount() {
        console.log("组件即将被卸载");
        window.onresize = null;
    }

受控与非受控组件

受控组件

当想要获取表单的一些内部状态时(表单中的checked,value属性等),就可以将表单的内部状态和组件的状态进行绑定,这样就形成受控组件

  • 受控组件: 让 表单控件 的内部状态 和我们 state 保持一致
class App extends Component {
  state = {
    name: "",
    checked: false,
  };
  render() {
    let { name, checked } = this.state;
    return <Fragment>
      <div>
        <input type="text"
          placeholder="请输入昵称"
          value={name}
          onChange={({ target }) => {
            this.setState({
              name: target.value
            });
          }} />
        <span>{name}</span>
      </div>
      <div>
        是否学习?:
        <input
          type="checkbox"
          checked={checked}
          onChange={({ target }) => {
            this.setState({
              checked: target.checked
            });
          }} />
      </div>
      <button onClick={() => {
        console.log(this.state);
      }}>提交数据</button>
    </Fragment>;
  }
}

在这里插入图片描述
在这里插入图片描述

非受控组件:

我们不需要同步 value 值(defaultValuedefaultChecked)
只是给表单控件一个初始值

      <div>
        <input type="text"
          placeholder="请输入昵称"
          defaultValue={name}
        />
        <span>{name}</span>
      </div>
      <div>
        是否学习?:
        <input
          type="checkbox"
          defaultChecked={checked}
        />
      </div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值