组件通信方式

父子组件通信

类组件

通过props

import React, { Component } from 'react'


// 父组件
export default class App extends Component {
    state = {
        num: 1
    }
    // 父组件中的方法执行的事情
    add=()=>{
        this.setState({
            num:this.state.num+1
        })
    }
    render() {
        return (
            <div>
                {/* 通过 */}
                <div>子组件中触发的加一:{this.state.num}</div>
                {/* 通过属性名={传递的值} 来向子组件传值   通过方法名={方法} 来向子组件传递一个方法*/}
                <App2 num={this.state.num} add={this.add}/>
            </div>
        )
    }
}
 
// 子组件
class App2 extends Component {
    // 子组件通过自身的方法,像父组件提交了一个功能,触发父组件的方法
    add = () => {
        // 触发父组件的传来的方法
        this.props.add()
 
    }
    render() {
        return (
            <div>
                <div>
                    {/* 通过this.props.属性名 来接受父组件传来的值 */}
                    父组件传来的数值:{this.props.num}
                </div>
                <button onClick={this.add}>加一</button>
            </div>
        )
    }

}

函数组件

import React,{useState} from 'react'
 
export default function App() {
    const [num,setNum] = useState(0)//定义一个变量num
    const add=()=>{
        setNum(num+1)//修改num,使之加一
    }
    return (
        <div>
            <div>子传父更改的值:{num}</div>
             {/* 通过属性名={传递的值} 来向子组件传值   通过方法名={方法} 来向子组件传递一个方法*/}
            <App2 num={num} add={add}/>
        </div>
    )
}
 
function App2(props) {
    const add = () => {
        // 触发父组件的传来的方法
        props.add()
 
    }
    return (
        <div>
            <div>
                {/* 通过props.属性名 来接受父组件传来的值 */}
                父组件传来的数值:{props.num}
            </div>
            <button onClick={add}>加一</button>
        </div>
    )
}

非父子通信

状态提升

import React, { Component } from 'react'
/* 
儿子2 想接受儿子1里面的数据,并实现加1,
*/
 
// 中间人
export default class App11 extends Component {
    state={
        acceptNum:0//用来接受儿子1传来的值
    }
 
    tranNum = (sub1Value) => {
        console.log("能接受到儿子1传来的值吗?",sub1Value);
        // 将儿子1传来的值放到父亲身上
        this.setState({
            acceptNum:sub1Value
        })
    }
    tranNum2 = (sub2Value) => {
        console.log("能接受到儿子2传来的值吗?",sub2Value);
        // 将儿子1传来的值放到父亲身上
        this.setState({
            acceptNum:sub2Value
        })
    }
    render() {
        return (
            <div>
 
                <Sub1 tranNum={this.tranNum} />
                <div>{this.state.acceptNum}</div>
                <hr />
                {/* 将儿子1传来的值,通过父亲转接,传给儿子2 */}
                <Sub2 sub1Num={this.state.acceptNum} tranNum2={this.tranNum2}/>
                <hr />
                {/* 儿子2更改后的的值传回给儿子1 */}
                <Sub1 sub2Num={this.state.acceptNum} />
 
            </div>
        )
    }
}
// 儿子1
class Sub1 extends Component {
    state = {
        num: 1
    }
    // 儿子1向父亲传递num里面的值
    transferFn = (num) => {
        this.props.tranNum(num)
    }
    render() {
        return (
            <div>
                <button onClick={this.transferFn.bind(this, this.state.num)}>Sub1向父亲传值</button>
                <div>拿到儿子2通过加一后传来的值{this.props.sub2Num}</div>
            </div>
        )
    }
}
 
// 儿子2
class Sub2 extends Component {
    // 儿子2修改了儿子1的值,并给父亲发了个指令
    addFn=(sub1Num)=>{
        var sub2Num = sub1Num+1
        this.props.tranNum2(sub2Num)
    }
    render() {
        return (
            <div>
                <div>儿子2经过父亲,拿到儿子1传来的值:{this.props.sub1Num}</div>
                <button onClick={this.addFn.bind(this,this.props.sub1Num)}>加一</button>
            </div>
        )
    }
}

不利于开发者维护

发布订阅模式

实际开发不会使用原生的发布订阅者模式,会用redux(基于发布订阅者封装好的)方法来实现这种非父子通信的模式

import React, { Component } from 'react'
 
export default class App extends Component {
    render() {
        return (
            <div>发布订阅</div>
        )
    }
}
var bus = {
    list:[],
    // 发布
    subscribe(callback) {
        console.log(callback);
        this.list.push(callback)
 
    },
    // 订阅
    publish(text) {//text传的参数
        // 遍历所有的list,将回调函数执行
        this.list.forEach(callback=>{
            callback&&callback(text)
        })
 
    }
}
// 订阅者
bus.subscribe((value)=>{//value接受发布者传来的参数
    console.log('111',value);
})
bus.subscribe(()=>{
    console.log("121");
})
bus.publish("传进去的参数1")
bus.publish("传进去的参数2")

context状态树

在新的context API中 React提供了一个createContext的方法,该方法返回了一个包含Provider,Consumer对象,需要注意的是:提供者一定要是消费者的某一层父级
(1)先定义全局context对象

(2)根组件引入GlobalContext,并使用GlobalContext.Provider(生产者)

(3)类组件中,任意组件引入GlobalContext并调用Context,使用GlobalContext.Consumer(消费者),返回一个函数,并传入value。

value.变量 获取数据

value.方法 获取方法

{
    // 必须要是一个箭头函数
    (value) => {
        return (//必须要return出去
          <div>
              <div>生产者提供的值:{value.num}</div>
              <button onClick={this.addFn.bind(this, value)}>加一</button>
          </div>
        )
     }
}

(4)函数式组件中,通过使用hooks提供的useContext来获取参数。

value.变量 获取数据

value.方法 获取方法

    const value = useContext(GlobalContext)
    console.log(value);
    const addFn = (value) => {
        value.changeNum()
    }
    return (
        <div>
            <div>生产者提供的值:{value.num}</div>
            <button onClick={() => addFn(value)}>加一</button>
        </div>
    )

实现代码:
类组件

import React, { Component, createContext } from 'react'
/* 
1、实现过程
(1)先定义全局context对象
 
(2)根组件引入GlobalContext,并使用GlobalContext.Provider(生产者)
 
(3)任意组件引入GlobalContext并调用Context,使用GlobalContext.Consumer(消费者)
*/
// 1、全局定义context对象
const GlobalContext = React.createContext()
 
// 生产者
export default class Context extends Component {
    state = {
        num: 1
    }
    render() {
        return (
            // 一定要为父标签,作为唯一的根标签
            <GlobalContext.Provider value={{
                num: this.state.num,//传递过去的值
                changeNum: (value) => {
                    this.setState({
                        num: this.state.num + 1
                    })
                }
            }}>
 
                <Consumer />
 
            </GlobalContext.Provider>
        )
    }
}
 
// 消费者
class Consumer extends Component {
    // 消费者向生产者发送的指令
    addFn = (value) => {
        // 执行生产者中的方法
        value.changeNum()
    }
    render() {
        return (
            <GlobalContext.Consumer>
                {
                    // 必须要是一个箭头函数
                    (value) => {
                        return (//必须要return出去
                            <div>
                                <div>生产者提供的值:{value.num}</div>
                                <button onClick={this.addFn.bind(this, value)}>加一</button>
                            </div>
                        )
                    }
                }
            </GlobalContext.Consumer>
        )
    }
}

函数组件-useContext()

没有引入useContext的写法

import React,{useState} from 'react'
// 1、全局定义context对象
const GlobalContext = React.createContext()
export default function App() {
    const [num,setNum] = useState(0)
    return (
        // 一定要为父标签,作为唯一的根标签
        <GlobalContext.Provider value={{
            num: num,//传递过去的值
            changeNum: (value) => {
                setNum(num + 1)
            }
        }}>
 
            <Sub1 />
 
        </GlobalContext.Provider>
    )
}
function Sub1(){
    const addFn=(value)=>{
        value.changeNum()
    }
    return (
        <GlobalContext.Consumer>
            {
                // 必须要是一个箭头函数
                (value) => {
                    console.log(value);
                    return (//必须要return出去
                        <div>
                            <div>生产者提供的值:{value.num}</div>
                            <button onClick={()=>addFn(value)}>加一</button>
                        </div>
                    )
                }
            }
        </GlobalContext.Consumer>
    )
}

引入useContext的写法

import React, { useState, useContext } from 'react'
// 1、全局定义context对象
const GlobalContext = React.createContext()
export default function App() {
    const [num, setNum] = useState(0)
    return (
        // 一定要为父标签,作为唯一的根标签
        <GlobalContext.Provider value={{
            num: num,//传递过去的值
            changeNum: (value) => {
                setNum(num + 1)
            }
        }}>
 
            <Sub1 />
 
        </GlobalContext.Provider>
    )
}
function Sub1() {
    const value = useContext(GlobalContext)
    console.log(value);
    const addFn = (value) => {
        value.changeNum()
    }
    return (
        <div>
            <div>生产者提供的值:{value.num}</div>
            <button onClick={() => addFn(value)}>加一</button>
        </div>
    )
}

注意 :
(1)提供者一定要是消费者的某一层父级

(2)消费者的结构必须必须要是一个箭头函数,而且必须要return出去

(3)函数组件的实现方式也是如此,只是存储的变量需要用useState

Redux状态管理

Redux术语
(1)Action

描述应用程序中发生了什么事件,有两个参数

    type:String,给action起一个描述性的名字,通常的格式“域/事件名称”,域:是action所属的特征或类别;事件名称:具体发生的事情

    action:可以有其他字段,其中包含有关发生的事情的附加信息,平常将该信息放在名为payload的字段中
// 创建action对象 
const action = { 
    type: "changeInputValue", // type属性是必须要写的,用于校验 
    value: e.target.value, // value代表要修改为什么值
 }

(2)reducer

是一个函数,接收当前的state(初始值)和一个action对象,必要是决定如何更新状态,并返回新状态。可以视为一个事件监听器,根据接受到的action类型处理事件

            state:指的是原始仓库里的状态

            action:指的是action新传递的状态

    函数内部的逻辑通常遵循的步骤:检查reducer是否关心action,如果关心则赋值state,使用新值更新state副本,然后返回新state;否则返回原来的state不变
//初始默认值 
const initialState = { 
    value: 0 
} 
//state:指的是原始仓库里的状态 
//action:指的是action新传递的状态 
function counterReducer(state = initialState, action) { 
    // 检查 reducer 是否关心这个 
    action if (action.type === 'counter/increment') { 
        // 如果是,复制 `state` 
        return { 
            ...state, // 使用新值更新 state 副本 
            value: state.value + 1 
        } 
    } 
    // 返回原来的 state 不变 
    return state 
}

通常用switch来遍历
(3)store
相当于一个仓库,当前redux应用的state存在与一个名为store的对象中

    通过传入reducer来创建

    通过getState()来获取仓库的内容,返回当前状态值
// 引入createStore对象 
import { createStore } from 'redux' // 引入reducer 
import reducer from './reducer' 
 
const store = createStore( reducer ); 
export default store; //获取当前状态值 
// 引入store 
import store from './store' var xxx = store.getState()

(4)dispatch
用来更新state的唯一方法是调用store.dispatch()并传入一个action对象,store 将执行所有 reducer 函数并计算出更新后的 state,调用 getState() 可以获取新 state。

store.dispatch({ type: 'counter/increment' }) 
console.log(store.getState()) // {value: 1}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值