为什么我不能在react.js中更新道具?

时间:2014-09-28 20:50:49

标签: javascript reactjs

为什么我们同时拥有stateprops?为什么我们只有一个数据来源?我想更新一个组件的props并让它自己及其所有孩子重新渲染。看似简单,但我无法弄清楚如何让组件更新自己的或其父级的道具。

感谢您的帮助。

6 个答案:

答案 0 :(得分:77)

React的理念是道具应该是不可变的和自上而下的。这意味着父母可以将其喜欢的任何道具值发送给孩子,但孩子不能修改自己的道具。你做的是对传入的道具作出反应然后,如果你愿意,根据传入的道具修改孩子的状态。

因此,您永远不会更新自己的道具或父母的道具。永远。您只需更新自己的状态,并对父母给出的道具值做出反应。

如果你想让一个动作发生在修改状态的东西上,那么你所做的就是将一个回调传递给它可以根据给定动作执行的子动作。然后,此回调可以修改父级的状态,然后可以在重新渲染时向子级发送不同的道具。

答案 1 :(得分:15)

回答为什么

的问题

在React中,道具向下流动,从父级到子级

这意味着当我们调用ReactDOM.render时,React可以呈现根节点,传递任何道具,然后忘记该节点。完成了。它已经渲染了。

这发生在每个组件上,我们渲染它,然后沿着树向下移动,深度优先。

如果组件可以改变其道具,我们将更改父节点可访问的对象,即使在父节点已经渲染之后也是如此。这可能会导致各种奇怪的行为,例如,user.name可能在应用程序的一个部分中具有一个值,而在不同部分中具有不同的值,并且它可能在下次触发渲染时自行更新

举一个虚构的例子:

// App renders a user.name and a profile
const App = (props) => 
  React.createElement('div', null, [
    props.user.name,
    React.createElement(Profile, props)
  ])

// Profile changes the user.name and renders it
// Now App has the wrong DOM.
const Profile = ({user}) => {
  user.name = "Voldemort" // Uh oh!
  return React.createElement('div', null, user.name);
}

// Render the App and give it props
ReactDOM.render(
  React.createElement(App, {user: {name: "Hermione"}}), 
  document.getElementById('app'))
);

我们渲染应用程序。它将“Hermione”输出到Shadow DOM。我们渲染个人资料,输出“Voldemort”。该应用程序现在错了。它应该说“Voldemort”,因为user.name是“Voldemort”,但我们已经输出了“Hermione”,现在改变它已经太晚了。

应用程序的不同部分的值会有所不同。

修改道具将是双向绑定

变异道具将是双向绑定的一种形式。我们将修改可能由树上方的另一个组件所依赖的值。

Angular 1有这个,你可以随时随地改变任何数据。为了工作,它需要一个周期性的$摘要。基本上,它会循环并重新渲染DOM,直到所有数据都完成传播。这是Angular 1如此缓慢的部分原因。

答案 2 :(得分:13)

在React中,stateprops提供不同的目标:state允许组件维护一些不断变化的值,而props是将这些值传播给子级的机制

儿童不能自行改变他们通过道具获得的价值,因为React设计师发现维护以这种方式构建的应用程序更容易。他们的观点是,当只允许一个组件更新某个状态时,更容易发现谁更改了它,并找到了bug的根源。

答案 3 :(得分:9)

组件本身会更改其状态,并且不会更改其自身,而是子项的道具

<Parent>
  <Child name={ this.state.childName } />
</Parent>

父级可以更改自己的状态并更改子级名称,但它会更改子级的道具。

EDIT1: 要将子事件中的事件调用到其父事件,您应该传递子事件,如下所示:

var Child = React.createClass({
  render: function() {
    return (<button onClick={ this.props.onClick }>Hey</button>);
  }
});

var Parent = React.createClass({
  onChildClick: console.log.bind(console), // will print the event..
  render: function() {
    return (<Child onClick={ this.onChildClick } />);
  }
});

React.renderComponent(<Parent />, document.body);

在此代码中,当您点击“儿童”按钮时,它会将事件传递给其父级。 传递事件的目的是解耦组件。也许在您的应用中,您需要执行此特定操作,但在您将拥有的其他应用中,您将以不同方式使用它。

答案 4 :(得分:0)

我的解决方案截然不同,但有些人可能会遇到它。在Chrome Dev工具上,它一直说我的道具是只读的,当我尝试进一步传递它们时,会出现错误。现在,其原因是因为我没有调用void main() { int *arr1, *arr2, *arr3, s1, s2, s3 = 0; cout << "Enter size of array 1:\t"; cin >> s1; cout << "\nEnter size of array 2:\t"; cin >> s2; arr1 = new int[s1]; arr2 = new int[s2]; arr3 = new int[s1 + s2]; cout << "\nEnter elements of array 1:\t"; for (int i = 0; i < s1; i++) { cin >> arr1[i]; } cout << "\nEnter elements of array 2:\t"; for (int i = 0; i < s2; i++) { cin >> arr2[i]; } for (int i = 0; i < s1 + s2; i++) { for(int j = 0; j < s2; j++) { if (arr1[i] == arr2[j]) { arr3[i] = arr1[i]; } } } s3 = sizeof(arr3); cout << "\nThe intersection of array 1 and array 2 is:\n"; for (int i = 0; i < s3; i++) { cout << arr3[i] << " "; } cout << endl; delete[] arr1; delete[] arr2; delete[] arr3; } 方法。相反,我是这样调用我的组件的:

render()

我添加了一个render方法,它解决了我无法传递道具的问题:

const Navigation = () =>{

    return (
        <div className="left-navigation">
            <ul>
                <Link to='/dashboard'><li>Home</li></Link>
                <Link to='/create-seedz'><li>Create Seedz</li></Link>
                <Link to='/create-promotion'><li>Create Promotion</li></Link>
                <Link to='/setting'><li>Setting</li></Link>
                <SignOutButton  />
            </ul>
        </div>
    );
}

希望这对某人有帮助。

答案 5 :(得分:-21)

与此处提供的答案相反,如果您不介意蔑视迂腐的反应方式,那么您实际上可以直接更新道具。&#34;反应方式。&#34;在React.js中,找到以下代码行:

Object.freeze(element.props);
Object.freeze(element);

并将其评论出来。瞧,可变的道具!