美文网首页前端笔记本前端
React组件之间的跳转及通信(传值)

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

作者: 春困秋乏冬眠夏打盹 | 来源:发表于2018-02-11 18:56 被阅读49次

    这篇先介绍了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
        }
    }
    

    相关文章

      网友评论

        本文标题:React组件之间的跳转及通信(传值)

        本文链接:https://www.haomeiwen.com/subject/ajnczxtx.html