Javascript 为什么我不能在 react.js 中更新 props?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26089532/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-22 22:19:01  来源:igfitidea点击:

Why can't I update props in react.js?

javascriptreactjs

提问by boom

Why do we have both stateand props? Why don't we just have one source of data? I'd like to update a component's propsand have it re-render itself and all of its children. Seems simple but I can't figure out how to let a component update its own or its parent's props.

为什么我们有stateprops?为什么我们不只有一个数据源?我想更新一个组件props并让它重新渲染它自己和它的所有子组件。看起来很简单,但我不知道如何让组件更新它自己或其父级的 props。

Thanks for any help.

谢谢你的帮助。

回答by Mike Driver

The React philosophy is that props should be immutable and top-down. This means that a parent can send whatever prop values it likes to a child, but the child cannot modify its own props. What you do is react to the incoming props and then, if you want to, modify your child's state based on incoming props.

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

So you don't ever update your own props, or a parent's props. Ever. You only ever update your own state, and react to prop values you are given by parent.

所以你永远不会更新你自己的道具,或者父母的道具。曾经。你只更新你自己的状态,并对父母给你的 prop 值做出反应。

If you want to have an action occur on a child which modifies something on the state, then what you do is pass a callback to the child which it can execute upon the given action. This callback can then modify the parent's state, which in turns can then send different props to the child on re-render.

如果你想让一个动作发生在一个修改状态的子节点上,那么你要做的就是将一个回调传递给它可以在给定动作上执行的子节点。这个回调然后可以修改父母的状态,然后可以在重新渲染时将不同的道具发送给孩子。

回答by superluminary

To answer the question of why

回答为什么的问题

In React, props flow downward, from parent to child.

在 React 中,props 向下流动,从parent 到 child

This means that when we call ReactDOM.render, React can render the root node, pass down any props, and then forget about that node. It's done with. It's already rendered.

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

This happens at each component, we render it, then move on down the tree, depth-first.

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

If a component could mutate its props, we would be changing an object that is accessible to the parent node, even after the parent node had already rendered. This could cause all sorts of strange behaviour, for example, a user.namemight have one value in one part of the app, and a different value in a different part, and it might update itself the next time a render is triggered.

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

To give a fictional example:

举一个虚构的例子:

// 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'))
);

We render app. It outputs "Hermione" to the Shadow DOM. We render the Profile, it outputs "Voldemort". The App is now wrong. It should say "Voldemort" because user.nameis "Voldemort", but we already output "Hermione", and it's too late to change it.

我们呈现应用程序。它将“Hermione”输出到 Shadow DOM。我们渲染配置文件,它输出“伏地魔”。该应用程序现在是错误的。应该说“Voldemort”,因为它user.name是“Voldemort”,但我们已经输出了“Hermione”,要改变它为时已晚。

The value will be different in different parts of the app.

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

Modifying Props would be two-way-binding

修改道具将是双向绑定的

Mutating props would be a form of two-way binding. We would be modifying values that might be relied on by another component higher up the tree.

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

Angular 1 had this, you could change any data anytime from wherever you were. In order to work, it needed a cyclical $digest. Basically, it would loop around and around, re-rendering the DOM, until all the data had finished propagating. This was part of the reason why Angular 1 was so slow.

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

回答by Valéry

In React, stateand propsserve different goals: stateallows a component to maintain some changing values, while propsare the mecanism to propagate those values to children.

在反应,stateprops服务于不同的目标:state可以使组件保持一定的变化值,而props对那些价值观传播到孩子mecanism。

Children are not allowed to alter by themselves the values they get via props just because React designers find it easier to maintain an application built this way. Their point is that when only one component is allowed to update some piece of state, it is easier to discover who altered it, and find the root of bugs.

不允许孩子们自己改变他们通过 props 获得的值,因为 React 设计者发现以这种方式构建的应用程序更容易维护。他们的观点是,当只允许一个组件更新某个状态时,更容易发现谁更改了它,并找到了错误的根源。

回答by Gal Schlezinger

the Component itself changes its state, and changes not its own, but the children's props.

Component 本身改变了它的状态,改变的不是它自己的而是孩子的props

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

Parent can change its own state and change the child name, but it will change the props for his children.

Parent 可以改变自己的 state 和改变 child 的名字,但是它会改变他的孩子的 props。

edit1: for calling events from the child to its parent, you should pass in the child an event handler like so:

编辑1:为了从子级调用事件到其父级,您应该向子级传递一个事件处理程序,如下所示:

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);

in this code, when you'll click on the Child's button, it will pass the event to its parent. the purpose of passing the events is decoupling the components. maybe in your app you need this specific action, but in another app you'll have, you'll use it differently.

在此代码中,当您单击子项的按钮时,它会将事件传递给其父项。传递事件的目的是解耦组件。也许在你的应用程序中你需要这个特定的操作,但在另一个应用程序中,你会以不同的方式使用它。

回答by Lewis Menelaws

My solution was fairly different but some people might run into it. On the Chrome Dev tools, it kept saying that my props were read-only and when I tried passing them down even further, I would get an error. Now, the reason why is because I wasn't invoking a render()method. I was instead calling my component like this:

我的解决方案完全不同,但有些人可能会遇到它。在 Chrome 开发工具上,它一直说我的 props 是只读的,当我尝试进一步传递它们时,我会得到一个错误。现在,原因是因为我没有调用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>
    );
}

I added a render method and it solved my issue of being able to pass props down:

我添加了一个渲染方法,它解决了我能够传递道具的问题:

class Navigation extends Component{
render(){
    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 user={this.props.user} signedOut={this.props.signedOut} authed={this.props.authed}/>
            </ul>
        </div>
    );
}
}

Hopefully this helps someone.

希望这有助于某人。

回答by joeyp

Contrary to the answers provided here, you actually canupdate props directly, if you don't mind defying the pedantic circlejerk about "the React way." In React.js, find the following lines of code:

与此处提供的答案相反,您实际上可以直接更新道具,如果您不介意挑战关于“React 方式”的迂腐迂腐。在 React.js 中,找到以下代码行:

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

and comment them out. Voila, mutable props!

并将它们注释掉。瞧,可变道具!