前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >react实践笔记:父子组件数值双向传递

react实践笔记:父子组件数值双向传递

原创
作者头像
zww_v5
修改2018-12-24 10:37:57
3.9K0
修改2018-12-24 10:37:57
举报
文章被收录于专栏:zwwv5zwwv5

    在编写 react 组件时,经常会遇到一个场景:子组件有个状态,可以通过内部的一个按钮进行切换;而父组件也可以通过一个按钮,同步去切换子组件的状态。比如侧边栏菜单的实现:顶部导航通过点击“筛选”按钮展开侧边栏,而侧边栏自身通过点击“箭头”按钮收起侧边栏。在这种场景下,当点击“筛选”按钮时,则是父组件将改变后的状态传递给子组件;而点击“箭头”按钮时,则是子组件自身状态的变化,同时也把这个状态传递回父组件。

     这是一个相当典型的父子组件数值的双向传递,本文将以上面场景为例讲解如何实现双向传递。

一、单向传递

    要实现侧边栏的功能,需要先了解父子组件各自单向传递的方式。

1、父组件传值给子组件

    父组件传值给子组件,主要是通过 props 的方式进行处理。具体示例如下:

代码语言:jsx
复制
//父组件
class ParentCom extends Component {
    constructor(props) {
        ...
    }

    render() {
        const title="传给子组件的标题";

        return (
            <div className={"parent"}>
                <ChildCom 
                    title={title} 
                 />
            </div>
        );
    }
}
    
//子组件
class ChildCom extends Component {
    constructor(props) {
        ...
    }

    render() {
        const {
            title
        } = this.props;

        return (
            <div className="child">
                <h3>{title}</h3>
            </div>
        );
    }
}

        父组件在 render 函数中定义了变量 title ,然后通过把这个变量赋值给子组件的 title 属性中。而在子组件中,在 render 函数中通过 react 的 props 对象取到刚传递过来的值。

2、子组件传值给父组件

    子组件传值给父组件,主要是通过调用父组件传递过来的回调函数来实现的。具体示例如下:

代码语言:jsx
复制
//父组件
class ParentCom extends Component {
    constructor(props) {
        ...

        this.callback = this.callback.bind(this);
    }

    callback(childState){
        // 记录下子组件传递过来的值
        this.childState = childState;
    }

    render() {
        const title="传给子组件的标题";

        return (
            <div className={"parent"}>
                <ChildCom 
                    title={title} 
                    callback={this.callback}
                 />
            </div>
        );
    }
}
    
//子组件
class ChildCom extends Component {
    constructor(props) {
        ...

        this.state = {
            show: false
        }

        this.showTrigger = this.showTrigger.bind(this);
    }

    showTrigger(){
        const {
            callback
        } = this.props;
        const show = !this.state.show;

        this.setState({
            show: show
        });

        if (callback) {
            // 将子组件改变后的状态值传给父级
            callback(show);
        }
    }

    render() {
        const {
            title
        } = this.props;

        return (
            <div className="child">
                <h3>{title}</h3>
                <button
                    onClick={this.showTrigger}
                >
                    改变子组件的状态
                </button>
            </div>
        );
    }
}

        父组件定义了一个回调函数 callback,用于接收子组件状态值。这里要注意的一点是,在 constructor 中通过 bind 方法将 callback 中的 this 强制指向父组件。这一步很关键,这是保证子组件执行回调函数时,能够访问父组件的关键。

        而子组件通过 props 获得回调函数后,在改变状态时,将改变后的状态值通过回调函数的参数传递给父组件。

二、完整的实例呈现

    了解了各自的单向传递后,要实现侧边栏的功能就很简单了。只需要将以下两个步骤合并在一起即可以实现。主要实现以下两个流程:

1、实现“筛选”按钮展开侧边栏的功能,具体路径是:

点击“筛选”按钮 》改变父组件记录的侧边栏展开状态,并触发父组件自身状态值的改变 》父组件重新渲染 》通过 props 传值给侧边栏 》侧边栏重新渲染,执行展开动作

代码语言:jsx
复制
//父组件
class ParentCom extends Component {
    constructor(props) {
        ...

        this.state = {
            childState: false
        }
        this.childState = false;

        this.childStateTrigger = this.childStateTrigger.bind(this);
    }

    childStateTrigger(){
        const childState = !this.childState;
        
        this.setState({
            childState: childState
        });
        this.childState = childState;
    }

    render() {
        const title="传给子组件的标题";
        const {
            childState
        } = this.state;

        return (
            <div className={"parent"}>
                <ChildCom 
                    title={title} 
                    show={childState}
                 />
                 <button
                    onClick={this.childStateTrigger}
                 >筛选</button>
            </div>
        );
    }
}
    
//子组件
class ChildCom extends Component {
    constructor(props) {
        ...

        this.state = {
            show: false
        }
    }

    componentWillReceiveProps(nextProps){
        //接收从父级传递过来的值
        if ('show' in nextProps) {
            this.setState({
                show: nextProps.show
            });
        }
    }

    render() {
        const {
            title
        } = this.props;

        const {
            show
        } = this.state;

        return (
            <div className="child">
                <h3>{title}</h3>
                <p>当前子组件的展示状态是:{show.toString()}</p>
            </div>
        );
    }
}

2、接下来就是实现侧边栏的收起功能,具体的路径如下:

点击“箭头”按钮 》 将侧边栏的展开状态变成收起状态,并调用父组件的回调函数 》 父组件在回调函数中,记录下子组件的状态值。具体代码如下:

代码语言:jsx
复制
//父组件
class ParentCom extends Component {
    constructor(props) {
        ...

        this.state = {
            childState: false
        }
        this.childState = false;

        this.childStateTrigger = this.childStateTrigger.bind(this);
        this.callback = this.callback.bind(this);
    }

    childStateTrigger(){
        const childState = !this.childState;
        
        this.setState({
            childState: childState
        });
        this.childState = childState;
    }

    callback(show){
        this.childState = show;

        console.log('更新父级的记录:', show);
    }

    render() {
        const title="传给子组件的标题";
        const {
            childState
        } = this.state;

        return (
            <div className={"parent"}>
                <ChildCom 
                    title={title} 
                    show={childState}
                    callback={this.callback}
                 />
                 <button
                    onClick={this.childStateTrigger}
                 >筛选</button>
            </div>
        );
    }
}
    
//子组件
class ChildCom extends Component {
    constructor(props) {
        ...

        this.state = {
            show: false
        }

        this.showTrigger = this.showTrigger.bind(this);
    }

    componentWillReceiveProps(nextProps){
        //接收从父级传递过来的值
        if ('show' in nextProps) {
            this.setState({
                show: nextProps.show
            });
        }
    }

    showTrigger(){
        const {
            callback
        } = this.props;

        const show = !this.state.show;

        this.setState({
            show: show
        });

        // 将子组件状态的改变传回父组件
        if (callback) {
            callback(show);
        }
    }

    render() {
        const {
            title
        } = this.props;

        const {
            show
        } = this.state;

        return (
            <div className="child">
                <h3>{title}</h3>
                <p>当前子组件的展示状态是:{show.toString()}</p>
                <button
                    onClick={this.showTrigger}
                >收起</button>
            </div>
        );
    }
}

    这里要一点要注意,在父组件的回调函数中,并没有把子组件的状态直接记录到父组件对应的状态值中。这是因为,对于子组件状态的变化,父组件只需要记录下就可以了,并不需要再次做重新的渲染。而且如果直接改变父组件的状态,则会引发父组件的重新渲染,从而触发侧边栏的属性传递。这一步虽然不会消耗多少性能,但显然是没有必要的过程。因此是通过 this.childState 的方式记录下侧边栏传递过来的状态值。

        通过以上两步,就实现了完成的侧边样的收起与展开的功能。其他父子组件数值的双向传递都可以参考这种方式进行处理。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、单向传递
    • 1、父组件传值给子组件
      • 2、子组件传值给父组件
      • 二、完整的实例呈现
        • 1、实现“筛选”按钮展开侧边栏的功能,具体路径是:
          • 2、接下来就是实现侧边栏的收起功能,具体的路径如下:
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档