React学习日志(组件通讯篇)

·  阅读 162

前言:Hello,我是一个野生的React玩家,在学习过程中发现学过的很容易忘记,在这里记录一下,还希望能认识一些React小伙伴,学习的路上太孤单啦。

正文:那么开始基础的组件之间的通讯,是我掌握的三种方式

  • props
  • context 基于createContext
  • 发布订阅
  1. 第一个是最普通的props传值,并传递改变自身状态的函数来实现子组件修改父组件状态。针对父孙组件之间则是逐级向下传递props,从头传到尾。针对兄弟组件则是通过父来建立联系(缺点是针对父孙和兄弟组件通讯代码看上去比较麻烦)

函数式组件 通过子组件修改父组件的count值,将count初始值和修改函数传入子组件

    // Parent.js 父组件
    import React from 'react';
    import {useState} from 'react';
    import Children from './children';
    function Parent() {
        const [count, setCount] = useState(0);

        return (
            <div>
                <span>{count}</span>
                <Children count={count} setCount={setCount}></Children>
            </div>
        )
    }

    export default Parent;
复制代码

函数式组件 子组件通过props获取count初始值和count修改函数并使用

    // Children.js 子组件
    import React from 'react';
    function Children(props) {
        function addCount() {
            props.setCount(props.count + 1);
        }
        return (
            <div>
                <button onClick={addCount}>add count</button>
                {/* other component example <Other {...props}> */}
            </div>
        )
    }

    export default Children;
复制代码
  1. 第二种方式通过Context来实现数据共享(优点是代码整洁,一步到位)

先创建对应的Context

    // context.js
    import {createContext} from 'react';
    export const TestContext = createContext({});
复制代码

函数式组件 将父组件包含在Context内,共享状态count并共享count的修改函数setCount

    // Parent.js 父组件
    import React from 'react';
    import {useState} from 'react';
    import Children from './children';
    import {TestContext} from './Context';

    function Parent() {
        const [count, setCount] = useState(0);

        return (
            <TestContext.Provider
                value={{
                    count: count,
                    setCount: setCount
                }}
            >
                <div>
                    <span>{count}</span>
                    <Children></Children>
                </div>
            </TestContext.Provider>
        )
    }

    export default Parent;
复制代码

函数式组件 子组件,包括任意该父组件下的子组件都可以这样来访问和修改count

    // Children.js 子组件
    import React from 'react';
    import {useContext} from 'react';
    import {TestContext} from './Context';

    function Children(props) {
        const {count, setCount} = useContext(TestContext);

        function addCount() {
            setCount(count + 1);
        }

        return (
            <div>
                <button onClick={addCount}>add count</button>
            </div>
        )
    }

    export default Children;
复制代码
  1. 第三种发布订阅模式(优点不必对父组件做什么封装,可以在任意位置1对1互联。缺点组件被多次使用即多次订阅会被一次发布全部触发,相同订阅的会被影响)

创建eventProxy.js用于实现发布订阅,即在使用on函数时往map里注册一个订阅事件,该事件可以有多个订阅函数。使用emit函数发布一个事件来触发订阅的函数

    const eventProxy = {
        map: {}, // 映射关系
        on: function(sign, fn) { // 订阅
            var map = this.map;
            if(!map[sign]) {
                map[sign] = [];
            }
            map[sign].push(fn);
        },
        emit: function(sign, backData) { // 发布
            var map = this.map;
            if(map[sign]) {
                map[sign].forEach(element => {
                    element(backData);
                });
            } else {
                throw "没有地方订阅";
            }
        }
    }

    export default eventProxy;
复制代码

函数式组件 父组件订阅一个事件,事件名为input,传入回调事件并接收返回参数,这里传入了count值给子组件

    import React from 'react';
    import {useState} from 'react';
    import Children from './children';
    import eventProxy from './eventProxy';

    function Parent() {
        const [count, setCount] = useState(0);

        eventProxy.on("input", (val) => {
            setCount(val)
        })
        return (
            <div>
                <span>{count}</span>
                <Children count={count}></Children>
            </div>
        )
    }

    export default Parent;
复制代码

函数式组件 子组件注册发布事件,事件名对应父组件注册的input事件,并传入回调参数

    import React from 'react';
    import eventProxy from './eventProxy';

    function Children(props) {

        function addCount() {
            eventProxy.emit("input", props.count + 1);
        }

        return (
            <div>
                <button onClick={addCount}>add count</button>
            </div>
        )
    }

    export default Children;
复制代码

总结:不知道还有没有别的方式,先记录这三种方法,感觉第三种还是挺坑的,同一个组件多次调用会互相影响(如select组件用这种方式控制选中赋值,当注册多个select的时候,一经发布所有的都会响应,结果所有select都变成一样的值了),不知道是否有解决的办法,非常期待留言,希望各位大佬别嫌弃。

分类:
前端
标签: