2020-9-14,状态机、组件通信、生命周期、DOM节点操作

本文详细介绍了React开发中的关键概念,包括状态机setState的异步特性,组件间的通信(父子、子父、非父子组件间),生命周期的各个阶段,以及如何在React中操作DOM节点,包括字符串、回调函数和createRef API的使用。

内容:状态机、组件通信、生命周期、DOM节点操作
日期:2020-09-14

一、状态机setState是一个异步操作

setState用来修改state中的初始状态,但是它异步操作,不能在setState之后马上获取到最新的数据。可以使用setState的第二个参数来获取到最新的数据

setState(要修改的数据对象,()=>{...})

在第二个参数(回调函数)中可以获取到state中最新的数据。

示例代码:

import React, { Component } from 'react'
export default class State extends Component {
    state = {
        num :100
    }
    addNum(){
        var n = this.state.num;
        n++;
        this.setState({ num : n },()=>{
            console.log(this.state.num,1111111111)//在回调函数中可以获取到state中最新的数据
        })
        console.log(this.state.num,222222222222)//此时获取到的数据不是最新的
    }
    render() {
        return (
            <div>
                <h2>数量:{ this.state.num }</h2>
                <button onClick={ ()=>this.addNum() }>点击增加</button>
            </div>
        )
    }
}

二、组件通信

1.父子组件

在父组件使用子组件时,通过自定义属性进行数据的传递,在子组件中通过props来接收。

(1)父组件

import React, { Component } from 'react'
import Child from './Child'
export default class Parent extends Component {
    state = {
        msg : '天道酬勤'
    }
    render() {
        return (
            <div>
                <h1>这是父组件</h1>
                <hr/>
                <Child data={this.state.msg} />
            </div>
        )
    }
}

(2)子组件

import React, { Component } from 'react'

class Child extends Component {
    render() {
        return (
            <div>
                <h2>这是子组件</h2>
                {/* 通过this.props来获取父组件传递的数据 */}
                <p>父组件的内容:{ this.props.data }</p>
            </div>
        )
    }
}
export default Child;

2.子父组件

使用自定义事件来实现子父组件通信

在父组件使用子组件时,传递一个自定义事件,用来让子组件触发或者进行数据的传递

import React, { Component } from 'react'
import Child from './Child'
export default class Parent extends Component {
    state = {
        msg : '天道酬勤',
        str:''
    }
    getStr(e){
        this.setState({ str:e })
    }
    render() {
        return (
            <div>
                <h1>这是父组件</h1>
                <p>子组件:{ this.state.str }</p>
                <hr/>
                <Child data={this.state.msg} sendStr={ (str)=>this.getStr(str) } />
            </div>
        )
    }
}

在子组件中,通过this.props.自定义事件名 来触发父组件的函数并传递参数

import React, { Component } from 'react'
class Child extends Component {
    send(){
        console.log(this)
        //调用父组件传递的函数
        this.props.sendStr('这是子组件的数据');
    }
    render() {
        return (
            <div>
                <h2>这是子组件</h2>
                {/* 通过this.props来获取父组件传递的数据 */}
                <p>父组件的内容:{ this.props.data }</p>
                <button onClick={ ()=>this.send() }>反馈数据</button>
            </div>
        )
    }
}
export default Child;

3.非父子组件

(1)设置一个公用容器

创建/src/bus.js,并引入events类中的EventEmitter事件监听器

const EventEmitter = require('events');
const MyEvent = new EventEmitter();
export default MyEvent;

(2)在项目启动文件中进行Component原型的挂载

/src/index.js

import React,{ Component } from 'react';
import bus from './bus'
Component.prototype.bus = bus;//将容器挂载到Component的原型上

(3)页面组件中使用

①数据发生端

this.bus.emit('事件名称','要传递的数据')

②数据接收端

constructor(){
    super();
    this.bus.on('事件名称',(形参)=>{
    	...
    })
}

三、生命周期

只有类组件才有生命周期,函数组件没有生命周期。

图示:

页面渲染期:

constructor 构造函数

UNSAFE_componentWillMount 组件将要挂载

render 组件渲染

componentDidMount 组件挂载完成

页面更新期:

UNSAFE_componentWillReceiveProps 子组件将要接收父组件传递的数据(数据在父组件中改变,然后传递给子组件时会触发此钩子函数)

shouldComponentUpdate 组件是否要更新数据(返回布尔值,true更新,false不更新)

render 组件渲染更新

UNSAFE_componentWillUpdate 组件将要更新,shouldComponentUpdate返回true时才执行

componentDidUpdate 组件更新完成,shouldComponentUpdate返回true时才执行

页面销毁期:

componentWillUnmount 组件将要销毁,组件不再显示时

四、state和props混用

state是页面组件的初始数据(当前组件可以对state中的数据进行任意修改)

props是父组件传递给子组件的数据(子组件只能读取props中的数据,不能直接修改)

子组件中的state要根据父组件传递过来的数据进行同步时,会存在一个数据不同步的问题

父组件:

import React, { Component } from 'react'
import Item from './Item'
export default class Home extends Component {
    state = {
        num:100
    }
    componentDidMount(){
        console.log('home组件挂载完成')
        this.setState({
            num:50
        })
    }
    render() {
        return (
            <div>
                <h1>home页面</h1>
                <hr/>
                <Item pdata={ this.state.num }></Item>
            </div>
        )
    }
}

子组件:

import React, { Component } from 'react'

export default class Item extends Component {
    state = {
        num:0
    }
    componentDidMount(){
        console.log('item组件挂载完成')
        this.setState({
            num:this.props.pdata//此时num的数据是父组件没有修改之前的数据,num是100
        })
    }
    render() {
        return (
            <div>
                <h2>item页面</h2>
                <p>home组件的数据:{ this.state.num }</p>
            </div>
        )
    }
}

为了解决state和props混用时出现的数据不同步问题,我们要把setState第一个参数写成一个函数,在这个函数中的第一个参数是当前组件的state数据,第二个参数是父组件传递过来的最新数据。

import React, { Component } from 'react'
export default class Item extends Component {
    state = { num:0 }
    componentDidMount(){
        console.log('item组件挂载完成')
        this.setState(function(state,props){
            state.num = props.pdata;
        })
    }
    render() {
        return (
            <div>
                <h2>item页面</h2>
                <p>home组件的数据:{ this.state.num }</p>
            </div>
        )
    }
}

setState的参数

可以是一个对象

可以是一个对象+一个回调函数

可以是一个函数

五、DOM节点操作

1.字符串

可以给标签添加ref属性,在组件挂载完成后就可以通过this.refs来DOM节点的操作

export default class Home extends Component {
    render() {
        return (
            <div>
                <h1 ref="myh1">home页面</h1>
            </div>
        )
    }
    componentDidMount(){
        this.refs.myh1.innerHTML = '向英雄致敬'
    }
}

2.回调函数

ref属性可以用在普通标签上,也可以使用在子组件上,通过DOM节点操作来实现组件之间通信。

import React, { Component } from 'react'
import Child from './Child'
export default class Home extends Component {
    render() {
        return (
            <div>
                {/* <Child ref="mychild"/> */}
                <Child ref={(e)=>this.setChild(e)} />
            </div>
        )
    }
    componentDidMount(){
        // this.refs.myh1.innerHTML = '向英雄致敬'
        // console.log(this.refs)
    }
    setChild(el){
        //此时el就是子组件
        // console.log(el)
        el.setState({
            msg:'向英雄致敬'
        })
    }
}

3.createRef API

react中给提供了一个createRef API方法,用它也可以来实现DOM节点操作

在构造函数中通过React.createRef来创建一个空的容器

constructor(){
    super();
    this.childEl = React.createRef();//this.childEl {current:null}
}

在页面中使用标签或者子组件时,通过ref进行赋值

<Child ref={ this.childEl } />

此时this.childEl.current就是子组件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值