React组件之间的跳转及通信(传值)

这篇先介绍了React组件之间传递值的几种类型及方式,最后还介绍了单页面应用开发过程中,遇到的兄弟组件之间的跳转及传值的两种方式。

React组件之间通信是单向的,数据只能由一方传到另一方。

组件之间的关系有:

  1. 父组件向子组件传递值
  2. 子组件向父组件传递值
  3. 兄弟组件之间通信


父组件向子组件传递值 (Parent=>Child)

父组件向一级子组件传递值,可以给子组件通过props传递。自上而下进行传递。

class Parent extends Component {
    render() {
        return <Child data={data} />; // 向子组件传递data值
    }
}
class Child extends Component {
    render() {
        return <p>{this.props.data}</p>; // 接收到父组件Parent传递来的data值
    }
}

父组件向二级子组件传递值,可以通过... 展开props属性,将父组件Parent的信息,简洁的传递给更深层级子组件。

class Child extends Component {
    render() {
        return <div>
            <p>{this.props.data}</p>
            <Child_Child {...this.props}/> {/* 将props解构,全部赋给二级子组件 */}
        </div>
    }
}
class Child_Child extends Component {
    render() {
        return <p>{this.props.data}</p>; // 接收到父组件Parent的值
    }
}

注:通过这种方式,将父组件的值传递给向子组件,父组件的props与state改变,也会导致子组件的生命周期改变。

子组件向父组件传递值 (Child=>Parent)

子组件向父组件通讯,同样需要父组件向子组件传递props,只是父组件传递的不是值,而是传递一个函数,这个函数的作用域为父组件。子组件调用这个函数,将子组件要传递的信息,作为参数,传递到父组件作用域中。父组件作用域中的该函数执行时,就能调用到这个参数了。

class Parent extends Component {
    state = {
        data: 'data'
    }

    getChildMessage (newData) {
        this.setState({
            data: newData
        })
    }

    render() {
        return <div>
            <Child fn={(data) => this.getChildMessage(data)} />
     //或者 <Child fn={this.getChildMessage} /> 
        </div>
    }
}
class Child extends Component {
    componentDidMount() {
        setTimeout(() => {
            this.props. getChildMessage('child-data');  // 调用父组件传来的函数,将数据作为参数传过去
        }, 1000);
    }    
    render() {...}
}

兄弟组件之间通信 (ChildA=>ChildB)

对于没有直接关联的两个组件,ChildA和ChildB之间,他们之间唯一的联系就是,它们有相同的父组件Parent。
如果我们想由A向B通讯,可以先从A向Parent通讯,再由Parent向B通讯。

class Parent extends Component {
    state = {
        data: 'data'
    }

    getChildMessage (newData) {
        this.setState({
            data: newData
        })
    }

    render() {
        return <div>
            <ChildA fn={(data) => this.getChildMessage(data)} />  {/* 父组件从子组件A获取到值 */}
            <ChildB data={this.state.data} />   {/* Parent向子组件B传值 */}
        </div>;
    }
}
class ChildA extends Component {
    componentDidMount() {
        setTimeout(() => {
            this.props.getChildMessage('child-data');  // 向Parent传值
        }, 1000);
    }
    render() {...}
}
class ChildB extends Component {
    render() {
        return <p>{this.props.data}</p>;  {/* 从Parent传来的值 */}
    }
}

这个方法存在一个问题是,当Parent的state发生变化,会触发Parent以及所属的子组件的生命周期。

兄弟组件之间的通讯,有没有更好的方式?
观察者模式 (发布者-订阅者)
发布者发布事件,订阅者监听事件 并做出反应。
。。。

在实际开发单页面应用时,遇到页面之间的跳转以及参数传递举例

1. 路由。

通过React的路由库,实现页面跳转,和页面之间的参数传递。

将A页面里获取到的数据,在页面跳转到B时,传给B页面。

// Parent 
import { HashRouter as Router, Route, Switch } from 'react-router-dom';
import ChildA from './ChildA';
import ChildB from './ChildB';

const App = () => {
    <Router>
        <Switch>
            <Route exact path="/" component={ChildA} />
            <Route path="/result/:name" component={ChildB} />
        </Switch>
    </Router>
};
// ChildA
import { withRouter } from 'react-router-dom';

class ChildA extends Component {
   ...
   this.props.history.push('/result/' + encodeURIComponent(name));
   ...
}
// this.props.history.push() 这个方法会触发组件页面之间的跳转
//ChildB
import { withRouter } from 'react-router-dom';

class ChildB extends Component {
    render () {
        return <div>{decodeURIComponent(this.props.match.params.name}</div>
    }
}
// this.props.match.params.name 这个props上的值可以获得路由参数传来的值

路由的方式切换页面,存在的一个问题是,用户可以通过浏览器回退功能,退回到上一个页面。如果你的单页面应用不可回退到前一个页面,这个方法就不适合了。

2. 不用路由,通过父级的一个函数,改变变量的值,来控制显示A页面还是B页面。

这种方式可以组件内控制返回任意页面。不能通过浏览器回退返回到前一个页面。

class Parent extends Component {
    state = {
        page: 0,
        name: null
    }

    go = (page, name) => {
        const state = { 
            page
        };

        if (name) {
            state.name = name;
        }

        this.setState(state);
    }

    render () {
        const { page, name } = this.state;
        // 父级根据参数确定跳转到哪
        if (page) {
            return <ChildB go={this.go} name={name} />;
        }
        
        return <ChildA go={this.go} name={name} />;
    }
}
render(<Parent />, document.getElementById('wrap'));
class ChildA extends Component {
    componentDidMount() {
        // 判断父级传来的name是否有值,来做不同操作
        if (this.props.name) { ... } else { ... }
    }
    ...{
        //如果要从A页面跳转到B页面。调用父级的go函数,传参 page=1,name=xxx
        this.props.go(1, name);
    }
}
class ChildB extends Compponent {
    ... {
        this.props.go(0);  // 重新返回A页面。“重新开始”的意思。page=0
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,454评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,553评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,921评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,648评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,770评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,950评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,090评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,817评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,275评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,592评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,724评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,409评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,052评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,815评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,043评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,503评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,627评论 2 350

推荐阅读更多精彩内容

  • 序 今年大前端的概念一而再再而三的被提及,那么大前端时代究竟是什么呢?大前端这个词最早是因为在阿里内部有很多前端开...
    一缕殇流化隐半边冰霜阅读 11,227评论 19 92
  • 说在前面 关于 react 的总结过去半年就一直碎碎念着要搞起来,各(wo)种(tai)原(lan)因(le)。心...
    陈嘻嘻啊阅读 6,850评论 7 41
  • react是以组合组件的形式组织的,那么组件间是如何传递信息的呢? 父组件向子组件通信 parent组件传给chi...
    DCbryant阅读 461评论 0 0
  • 【爱有病】 如果这是你要的(或许你什么都没有想)那我就保持沉默好了但我无法保证流水是否会干枯对山呼喊有回音的是什么...
    夕颜1977阅读 211评论 1 4
  • 这座城市,忽得秋风萧瑟 依旧T恤傍身的我 确实略感寒意 下午牙科诊所出来 时间尚早 去图书馆寻觅想要查询的书籍 时...
    陆伸阅读 179评论 0 0