Quel est le modèle recommandé pour effectuer un setState sur un parent à partir d'un composant enfant.
var Todos = React.createClass({
getInitialState: function() {
return {
todos: [
"I am done",
"I am not done"
]
}
},
render: function() {
var todos = this.state.todos.map(function(todo) {
return <div>{todo}</div>;
});
return <div>
<h3>Todo(s)</h3>
{todos}
<TodoForm />
</div>;
}
});
var TodoForm = React.createClass({
getInitialState: function() {
return {
todoInput: ""
}
},
handleOnChange: function(e) {
e.preventDefault();
this.setState({todoInput: e.target.value});
},
handleClick: function(e) {
e.preventDefault();
//add the new todo item
},
render: function() {
return <div>
<br />
<input type="text" value={this.state.todoInput} onChange={this.handleOnChange} />
<button onClick={this.handleClick}>Add Todo</button>
</div>;
}
});
React.render(<Todos />, document.body)
J'ai un tableau d'articles à faire qui sont conservés dans l'état du parent. Je veux accéder à l'état du parent et ajouter un nouvel élément todo, à partir du composant TodoForm
s handleClick
. Mon idée est de faire un setState sur le parent, ce qui rendra l'élément todo nouvellement ajouté.
setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the MyModal component.
Réponses:
Dans votre parent, vous pouvez créer une fonction comme celle
addTodoItem
qui effectuera le setState requis, puis passera cette fonction comme accessoire au composant enfant.var Todos = React.createClass({ ... addTodoItem: function(todoItem) { this.setState(({ todos }) => ({ todos: { ...todos, todoItem } })); }, render: function() { ... return <div> <h3>Todo(s)</h3> {todos} <TodoForm addTodoItem={this.addTodoItem} /> </div> } }); var TodoForm = React.createClass({ handleClick: function(e) { e.preventDefault(); this.props.addTodoItem(this.state.todoInput); this.setState({todoInput: ""}); }, ... });
Vous pouvez appeler
addTodoItem
dans le handleClick de TodoForm. Cela fera un setState sur le parent qui rendra l'élément todo nouvellement ajouté. J'espère que vous avez l'idée.Violon ici.
la source
<<
opérateurthis.state.todos << todoItem;
ici?this.state
directement. Mieux vaut utiliser setState fonctionnel. reactjs.org/docs/react-component.html#setstateCe sont tous essentiellement corrects, je pensais juste que je voudrais signaler la nouvelle documentation officielle (ish) de réaction qui recommande essentiellement: -
Voir https://reactjs.org/docs/lifting-state-up.html . La page fonctionne également à travers un exemple.
la source
Vous pouvez créer une fonction addTodo dans le composant parent, la lier à ce contexte, la transmettre au composant enfant et l'appeler à partir de là.
// in Todos addTodo: function(newTodo) { // add todo }
Ensuite, dans Todos.render, vous feriez
<TodoForm addToDo={this.addTodo.bind(this)} />
Appelez ceci dans TodoForm avec
this.props.addToDo(newTodo);
la source
bind(this)
au moment de passer la fonction, il ne lancait pas d'erreur de telle fonctionthis.setState is not a function
.Pour ceux qui maintiennent l'état avec le React Hook
useState
, j'ai adapté les suggestions ci-dessus pour créer une application de curseur de démonstration ci-dessous. Dans l'application de démonstration, le composant de curseur enfant conserve l'état du parent.La démo utilise également
useEffect
hook. (et moins important,useRef
crochet)import React, { useState, useEffect, useCallback, useRef } from "react"; //the parent react component function Parent() { // the parentState will be set by its child slider component const [parentState, setParentState] = useState(0); // make wrapper function to give child const wrapperSetParentState = useCallback(val => { setParentState(val); }, [setParentState]); return ( <div style={{ margin: 30 }}> <Child parentState={parentState} parentStateSetter={wrapperSetParentState} /> <div>Parent State: {parentState}</div> </div> ); }; //the child react component function Child({parentStateSetter}) { const childRef = useRef(); const [childState, setChildState] = useState(0); useEffect(() => { parentStateSetter(childState); }, [parentStateSetter, childState]); const onSliderChangeHandler = e => { //pass slider's event value to child's state setChildState(e.target.value); }; return ( <div> <input type="range" min="1" max="255" value={childState} ref={childRef} onChange={onSliderChangeHandler} ></input> </div> ); }; export default Parent;
la source
useEffect
? Pourquoi avons-nous besoin de stocker les données à la fois dans l'état parent et enfant?parentSetState={(obj) => { this.setState(obj) }}
la source
J'ai trouvé la solution simple et fonctionnelle suivante pour passer des arguments d'un composant enfant au composant parent:
//ChildExt component class ChildExt extends React.Component { render() { var handleForUpdate = this.props.handleForUpdate; return (<div><button onClick={() => handleForUpdate('someNewVar')}>Push me</button></div> ) } } //Parent component class ParentExt extends React.Component { constructor(props) { super(props); var handleForUpdate = this.handleForUpdate.bind(this); } handleForUpdate(someArg){ alert('We pass argument from Child to Parent: \n' + someArg); } render() { var handleForUpdate = this.handleForUpdate; return (<div> <ChildExt handleForUpdate = {handleForUpdate.bind(this)} /></div>) } } if(document.querySelector("#demo")){ ReactDOM.render( <ParentExt />, document.querySelector("#demo") ); }
Regardez JSFIDDLE
la source
Si vous travaillez avec un composant de classe en tant que parent, un moyen très simple de passer un setState à un enfant consiste à le transmettre dans une fonction de flèche. Cela fonctionne car il définit un environnement hissé qui peut être transmis:
class ClassComponent ... { modifyState = () =>{ this.setState({...}) } render(){ return <><ChildComponent parentStateModifier={modifyState} /></> } }
la source