ReactJS组件之间通信

最近在学习react.js,不得不说第一次接触组件化开发很神奇,当然也很不习惯。
react的思想还是蛮独特的,当然围绕react的一系列自动化工具也是让我感觉亚历山大
今天总结一下react组件之间的通信,权当是自己的学习笔记:

reactJs中数据流向的的特点是:单项数据流

react组件之间的组合不知道为什么给我一种数据结构当中树的感觉,数据就是从根节点(顶端或其他子树的顶端)“流”下来,大概就是这个样子:

比如这是一个组件树,数据就可以从main组件流到jumbotron组件、queationList组件、form组件,类似的queation组件的数据也可以流到下边的question组件里边。

但是很遗憾,这个从上到下的数据流动,只能解决很少的问题,还有一部分的数据流动就是类似从jumbotron组件到form组件的这样的兄弟组件的流动形式,或者隔着几个层级的数据流动,再或者子组件发生了数据的变化,想通知父组件,数据流向从子组件到父组件流,这些问题才是大多数的开发者需要面临的问题。
所以这篇笔记总结下基础的组件通信:

数据从父组件到子组件

最简单的通信就是父子间的通信,比如上边图上的有个jsonObj从main流进了QueationList
参考代码:

//这里模拟出几条数据
var jsonObj=[
    {name:"A",question:"从小被人打怎么办?",TextArea:"习惯就好了",applaud:35,disagree:1},{name:"B",question:"长的太帅被人砍怎么办?",TextArea:"食屎啦你",disagree:10},{name:"C",question:"因为太胖被人摸怎么办?",TextArea:"享受就好了",disagree:45},{name:"D",question:"被老师打不开心",TextArea:"用钱打脸",disagree:6},{name:"E",question:"不爱洗澡怎么办?",TextArea:"打一顿就好了",disagree:9}
]

var QuestionList=React.createClass({
    prepareToRender:function(list){
        var array=[];
        for(var i=0;i<list.length;i++){
            array.push(<Question obj={list[i]}   key={i}/>);
        }
        return array;
    },render:function(){
        var array=this.prepareToRender(this.props.jsonObj);
        return <div>{array}</div>;
    }
});
var Main = React.createClass({
    //开始渲染
    render: function () {
        return (
            <div>
                <div className="container col-md-6 col-md-offset-3">
                    <div className="container-fluid">
                        <QuestionList jsonObj={jsonObj}  />
                    </div>
            </div>
        );
    }
});
ReactDOM.render(
    <Main />,document.getElementById('container')
);

代码写的不怎么规范,但是数据的传递就是这样的:
<QuestionList jsonObj={jsonObj} />
这样就可以把父组件的数据带到子组件里边

数据从子组件到父组件

理论上来说数据只能是单向的,所以不借助插件数据还真不好从子组件到父组件,一种很简单的手段是回调函数:
在父组件当中写个回调函数,然后传递到子组件,什么时候子组件数据变化了,直接调这个回调函数就可以了。

比如现在的jumbotron的按钮被点击了,我们想把被点击这个事件发给它的父组件也就是main组件,那么我们可以这个做:

var Jumbotron = React.createClass({
    handleClick: function () {
        this.props.openTheWindow(false);
    },render: function () {
        return (
                <div className="row">
                    <div className="col-md-6  col-md-offset-3">
                        <button type="button" className="btn btn-default btn-lg" onClick={this.handleClick}>开始体验
                        </button>
                    </div>
                </div>
            </div>
        );
    }
});

var Main = React.createClass({
    getInitialState: function () {
        return {
            openTheWindow: true
        };
    },//开始给子组件一个回调函数,用来做子组件给父组件通信使用
    buttonResponse:function(windowSatus){
        this.setState({openTheWindow : windowSatus});
    },//开始渲染
    render: function () {
        console.log(jsonObj)
        return (
            <div>
                <Jumbotron openTheWindow={this.buttonResponse}/>
            </div>
        );
    }
});
ReactDOM.render(
    <Main />,document.getElementById('container')
);

子组件通知父组件状态变化就是这样,就好像是儿子找爸爸要零花钱,零花钱以及给不给都是爸爸说了算的。

兄弟组件之间的通信

这个其实应该是一个动态应用中最常见的通信,比如jubotron组件的点击按钮,form组件的表单出现:
这就是一个典型的兄弟之间的通信:

兄弟节点其实可以就是子父通信&&父子通信的叠加
首先按钮被点击,子组件通知负组件这个事件,然后父组件把这个消息带给另一个子组件
下边是个点击按钮显示表单的例子:

/**
 * Created by niuGuangzhe on 2016/9/10.
 */
var Jumbotron = React.createClass({
    handleClick: function () {
        this.props.openTheWindow(false);
    },render: function () {
        return (
            <div className="jumbotron">
                <div className="row">
                    <div className="col-md-6  col-md-offset-3">
                        <button type="button" className="btn btn-default btn-lg" onClick={this.handleClick}>开始体验
                        </button>
                    </div>
                </div>
            </div>
        );
    }
});

var Form = React.createClass({
    getInitialState:function(){
        return {
            inputTitle:"请输入标题",mainBody:"在此输入正文"
        };
    },//点击按钮触发事件:清除所有已经输入的文字
    cleanText:function(){
        this.setState({
            inputTitle:"",mainBody:""});
    },//表单监视事件
    handleChange(name,e) {
        var newState = {};
        console.log(name);
        newState[name] =event.target.value;
        this.setState(newState);
    },render: function () {
        return (
            <div style={{display:this.props.openTheWindow?"none":"block"}}>
                <form role="form">
                    <div className="form-group">
                        <label htmlFor="title">标题</label>
                        <input type="text" className="form-control" id="title" name="inputTitle" value={this.state.inputTitle} onChange={this.handleChange.bind(this,"inputTitle")}/>
                    </div>

                    <div className="form-group">
                        <label htmlFor="textArea">正文</label>
                        <textarea className="form-control" rows="3" id="textArea" name="mainBody" value={this.state.mainBody} onChange={this.handleChange.bind(this,"mainBody")}></textarea>
                    </div>
                    <div className="row">

                        <input type="button" className="btn btn-default pull-right leaveMeAlone" value="取消"  onClick={this.cleanText}/>
                        <input type="submit" className="btn btn-primary pull-right leaveMeAlone" value="提交"/>
                    </div>
                </form>
            </div>
        )
    }
})


var Main = React.createClass({
    getInitialState: function () {
        return {
            openTheWindow: true
        };
    },//开始渲染
    render: function () {
        console.log(jsonObj)
        return (
            <div>
                <Jumbotron openTheWindow={this.buttonResponse}/>
                <div className="container col-md-6 col-md-offset-3">
                    <Form openTheWindow={this.state.openTheWindow}/>
                </div>
            </div>
        );
    }
});
ReactDOM.render(
    <Main />,document.getElementById('container')
);

就是这样,

其实上边的代码是我从之前的没事干做的一个单页面上拿过来改的,为了不出现代码无法运行的问题,下边贴出所有代码:

/**
 * Created by niuGuangzhe on 2016/9/10.
 */
var Jumbotron = React.createClass({
    handleClick: function () {
        this.props.openTheWindow(false);
    },render: function () {
        return (
            <div className="jumbotron">
                <div className="row">
                    <div className="col-md-6  col-md-offset-3">
                        <h2 className="colorChange">React+bootstrap简单实例</h2>
                    </div>
                </div>
                <div className="row">
                    <div className="col-md-6  col-md-offset-3">
                        <p className="colorChange">上手体验:第一次尝试组件化开发</p>
                    </div>
                </div>
                <div className="row">
                    <div className="col-md-6  col-md-offset-3">
                        <button type="button" className="btn btn-default btn-lg" onClick={this.handleClick}>开始体验
                        </button>
                    </div>
                </div>
            </div>
        );
    }
});

var Form = React.createClass({
    getInitialState:function(){
        return {
            inputTitle:"请输入标题","inputTitle")}/>
                    </div>

                    <div className="form-group">
                        <label htmlFor="textArea">标题</label>
                        <textarea className="form-control" rows="3" id="textArea" name="mainBody" value={this.state.mainBody} onChange={this.handleChange.bind(this,"mainBody")}></textarea>
                    </div>
                    <div className="row">

                        <input type="button" className="btn btn-default pull-right leaveMeAlone" value="取消"  onClick={this.cleanText}/>
                        <input type="submit" className="btn btn-primary pull-right leaveMeAlone" value="提交"/>
                    </div>
                </form>
            </div>
        )
    },//监测从新渲染
    componentDidUpdate:function(){
        console.log("子组件重新渲染;");
    }
})

var Question = React.createClass({
    getInitialState : function(){
        return {
            click:true,disClick:true
        };
    },numberHandle:function(){
        if(this.state.click===true){
            //奇数次点击,开始增加数据
            this.props.obj.applaud+=1;
            this.setState({click:false});
        }else{
            //偶数次点击,减去数据
            this.props.obj.applaud-=1;
            this.setState({click:true});
        }
    },decreateHandle:function(){
        if(this.state.disClick===true){
            //奇数次点击,开始增加数据
            this.props.obj.applaud-=1;
            this.setState({disClick:false});
        }else{
            //偶数次点击,减去数据
            this.props.obj.applaud+=1;
            this.setState({disClick:true});
        }
    },render: function () {
        return (
            <div className="row leaveMe">
                <div className="col-md-2">
                    <div className="col-md-12">
                        <button className="btn col-md-12 " onClick={this.numberHandle}>{this.props.obj.applaud-this.props.obj.disagree}<br/><span
                            className="glyphicon glyphicon-chevron-up"></span></button>
                    </div>
                    <span>&ensp;</span>
                    <div className="col-md-12">
                        <button className="btn col-md-12" onClick={this.decreateHandle}><span
                            className="glyphicon glyphicon-chevron-down"></span>
                        </button>
                    </div>
                </div>
                <div className="col-md-10  bs-callout bs-callout-info">
                    <h4>{this.props.obj.question}</h4>
                    <p>{this.props.obj.TextArea}</p>
                </div>
            </div>
        );
    }
});

var QuestionList=React.createClass({
    prepareToRender:function(list){
        var array=[];
        for(var i=0;i<list.length;i++){
            array.push(<Question obj={list[i]}   key={i}/>);
        }
        return array;
    },render:function(){
        var array=this.prepareToRender(this.props.jsonObj);
        return <div>{array}</div>;
    }
});


//这里模拟出几条数据
var jsonObj=[
    {name:"A",question:"因为太胖被人摸奶怎么办?",TextArea:"用钱打ta脸",disagree:9}
]

var Main = React.createClass({
    getInitialState: function () {
        return {
            openTheWindow: true
        };
    },//开始渲染
    render: function () {
        console.log(jsonObj)
        return (
            <div>
                <Jumbotron openTheWindow={this.buttonResponse}/>
                <div className="container col-md-6 col-md-offset-3">
                    <Form openTheWindow={this.state.openTheWindow}/>
                    <br/><br/>
                    <div className="container-fluid">
                        <QuestionList jsonObj={jsonObj}  />
                    </div>
                </div>
            </div>
        );
    },//    执行hook函数:重新渲染完成的时候调这个函数
    componentDidUpdate:function(){
        console.log(this.state.openTheWindow);
    }
});
ReactDOM.render(
    <Main />,document.getElementById('container')
);

最后就是一个很重要的问题:就是多层级的据数据传输,如果还用这个方式来传播的话,效率貌似是个大问题,解决办法看大家的做法目前暂时还是flux之类的其他框架,等研究出来单独写篇文章吧

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom