Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vue子组件为什么不能修改父组件传过来的props; 如果修改了,vue又是如何监听到并给出警告的呢? #8

Open
Diazhao opened this issue Jun 27, 2019 · 2 comments

Comments

@Diazhao
Copy link
Owner

Diazhao commented Jun 27, 2019

首先,第一个问题,不能修改父组件传进来的属性props,主要是为了做到保障单向数据流。
假设在这里我们可以随意修改的话,如果在父组件中这一状态值传递给了多个子组件,其中任意一个子组件的修改都会影响其他子组件的状态,而这样会造成我们的组件关系混乱,数据流向不可控,子组件的状态也不可预测。
所以,vue在内部如果监听到有子组件想要修改父组件传过来的值的时候,便会发出警告。不建议这样操作。
第二个问题,vue内部又是怎样做到监听修改,给出警告的呢?
在vue的源码中可以找到, /src/core/instance/state.js中,初始化props的时候,在开发环境的时候,是这样定义props的每一项值的,

      defineReactive(props, key, value, () => {
        if (!isRoot && !isUpdatingChildComponent) {
          warn(
            `Avoid mutating a prop directly since the value will be ` +
            `overwritten whenever the parent component re-renders. ` +
            `Instead, use a data or computed property based on the prop's ` +
            `value. Prop being mutated: "${key}"`,
            vm
          )
        }
      })

如上所示,defineReactive接收的第四个值是一个默认的setter,

export function defineReactive (
  obj: Object,
  key: string,
  val: any,
  customSetter?: ?Function,
  shallow?: boolean
) {

如果在开发环境的时候,会调用这个setter,给出warning。

@Diazhao
Copy link
Owner Author

Diazhao commented Jun 27, 2019

那么接下来还有一个问题,react中父子组件之间的传值是怎样操作的呢,单向数据流又是如何操作?

@Diazhao
Copy link
Owner Author

Diazhao commented Jul 2, 2019

如下所示,在子组件中通过this.props指向父组件中为子组件中绑定的属性。

      <div>
        {this.props.text}
        <br />
        <button onClick={this.props.refreshParent}>
            更新父组件
        </button>
      </div>

同样的,子组件中需要调用父组件的方法的时候,父组件中为子组件绑定回调函数,在子组件中通过this.props调用到即可。

render(){
    return (
      <div>
        <h1>父子组件沟通</h1>
        <button onClick={this.refreshChild()} >
            更新子组件
        </button>
        <Child 
          text={this.state.childText || "子组件未更新"} 
          refreshParent={this.refreshParent.bind(this)}
        />
    )
}

另外需要再提一下,vue中虽然有双向绑定的概念,但是,这与vue单向数据流的设计理念是不冲突的。
vue中通过v-model实现了数据与view的“双向数据流”,但这个v-model其实起到的是一个语法糖的作用,vue中组件间的数据流向,还是单向的。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant