web-dev-qa-db-fra.com

Pourquoi ne puis-je pas mettre à jour les accessoires dans react.js?

Pourquoi avons-nous à la fois state et props? Pourquoi n'avons-nous pas une seule source de données? Je souhaite mettre à jour la variable props d'un composant et le redonner à lui-même et à tous ses enfants. Cela semble simple, mais je ne vois pas comment laisser un composant mettre à jour ses propres accessoires ou ceux de son parent.

Merci pour toute aide.

43
boom

La philosophie de React est que les accessoires doivent être immuables et descendants. Cela signifie qu'un parent peut envoyer toutes les valeurs d'accessoires qu'il souhaite à un enfant, mais que l'enfant ne peut pas modifier ses propres accessoires. Ce que vous faites, c'est réagir aux accessoires entrants puis, si vous le souhaitez, modifier l'état de votre enfant en fonction des accessoires entrants.

Donc, vous ne mettez jamais à jour vos propres accessoires, ou les accessoires d'un parent. Déjà. Vous ne mettez à jour que votre propre état et réagissez aux valeurs prop que vous donne le parent.

Si vous souhaitez qu'une action sur un enfant modifie quelque chose sur l'état, vous passez un rappel à l'enfant qu'il peut exécuter sur l'action donnée. Ce rappel peut alors modifier l'état du parent, qui à son tour peut ensuite envoyer différents accessoires à l'enfant lors du rendu ultérieur.

74
Mike Driver

Dans React, state et props servent différents objectifs: state permet à un composant de conserver certaines valeurs changeantes, alors que props est le mécanisme permettant de propager ces valeurs aux enfants.

Les enfants ne sont pas autorisés à modifier eux-mêmes les valeurs qu'ils obtiennent via des accessoires simplement parce que les concepteurs de React trouvent qu'il est plus facile de maintenir une application construite de cette manière. Leur argument est que, lorsqu'un seul composant est autorisé à mettre à jour un élément de l'état, il est plus facile de découvrir qui l'a modifié et de trouver la racine des bogues.

13
Valéry

Pour répondre à la question de savoir pourquoi

Dans React, les accessoires descendent de parent à enfant .

Cela signifie que lorsque nous appelons ReactDOM.render, React peut rendre le nœud racine, transmettre tous les accessoires, puis oublier ce nœud. C'est fait avec. C'est déjà rendu. 

Cela se produit à chaque composant, nous le rendons, puis nous descendons dans l’arbre, en profondeur.

Si un composant pouvait muter ses accessoires, nous changerions un objet accessible au nœud parent, même après que le nœud parent ait déjà été rendu. Cela pourrait entraîner toutes sortes de comportements étranges, par exemple, un user.name pourrait avoir une valeur dans une partie de l'application et une valeur différente dans une autre, et il pourrait se mettre à jour lors du prochain déclenchement d'un rendu.

Pour donner un exemple fictif:

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

Nous rendons app. Il sort "Hermione" dans le DOM Shadow. Nous rendons le profil, il génère "Voldemort". L'application est maintenant fausse. Il devrait dire "Voldemort" car user.name est "Voldemort", mais nous avons déjà sorti "Hermione", et il est trop tard pour le changer. 

La valeur sera différente dans différentes parties de l'application.

Modification des accessoires serait une liaison bidirectionnelle

La mutation des accessoires serait une forme de liaison bidirectionnelle. Nous modifierions les valeurs sur lesquelles un autre composant pourrait s’appuyer plus haut dans l’arbre.

Angular 1 avait ceci, vous pouvez modifier n’importe quelle donnée à tout moment, où que vous soyez. Pour fonctionner, il avait besoin d’un $ digest condensé. En gros, il tournait en boucle, restituant le DOM, jusqu'à ce que toutes les données aient fini de se propager. Cela faisait partie de la raison pour laquelle Angular 1 était si lent.

12
superluminary

la composante elle-même change de état et ne change pas de sienne mais de props.

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

Le parent peut changer son propre état et changer le nom de l'enfant, mais cela changera les accessoires pour ses enfants.

edit1: pour appeler des événements de l'enfant à son parent, vous devez lui transmettre un gestionnaire d'événements comme suit:

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

dans ce code, lorsque vous cliquerez sur le bouton de l'enfant, l'événement sera transmis à son parent . le but de transmettre les événements est de découpler les composants. dans votre application, vous avez peut-être besoin de cette action spécifique, mais dans une autre application, vous l'utiliserez différemment.

8
Gal Schlezinger

Ma solution était assez différente, mais certaines personnes pourraient la rencontrer. Sur les outils de développement de Chrome, il n'arrêtait pas de dire que mes accessoires étaient en lecture seule et que, lorsque j'essayais de les transmettre encore davantage, une erreur se produisait. La raison en est que je n’appelais pas de méthode render(). J'appelais plutôt mon composant comme ceci:

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

J'ai ajouté une méthode de rendu et cela a résolu mon problème de pouvoir transmettre des accessoires:

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

Espérons que cela aide quelqu'un.

0
Lewis