Каков рекомендуемый шаблон для выполнения setState родительского элемента из дочернего компонента.
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)
У меня есть массив задач, которые хранятся в родительском состоянии. Я хочу , чтобы получить доступ состояния родителя и добавить новый пункт TODO, из TodoForm
«S handleClick
компоненты. Моя идея состоит в том, чтобы сделать setState для родителя, который будет отображать только что добавленный элемент todo.
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.
Ответы:
В своем родителе вы можете создать функцию,
addTodoItem
которая будет выполнять требуемый setState, а затем передать эту функцию в качестве реквизита дочернему компоненту.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: ""}); }, ... });
Вы можете вызвать
addTodoItem
метод handleClick в TodoForm. Это сделает setState для родительского элемента, который отобразит только что добавленный элемент todo. Надеюсь, вы уловили идею.Поиграй здесь.
источник
<<
операторthis.state.todos << todoItem;
?this.state
Непосредственная мутация - плохая практика . Лучше использовать функциональный setState. reactjs.org/docs/react-component.html#setstateВсе это по сути правильно, я просто подумал, что укажу на новую (ish) официальную документацию по реагированию, которая в основном рекомендует: -
См. Https://reactjs.org/docs/lifting-state-up.html . На странице также работает пример.
источник
Вы можете создать функцию addTodo в родительском компоненте, привязать ее к этому контексту, передать ее дочернему компоненту и вызвать оттуда.
// in Todos addTodo: function(newTodo) { // add todo }
Затем в Todos.render вы бы сделали
<TodoForm addToDo={this.addTodo.bind(this)} />
Вызовите это в TodoForm с помощью
this.props.addToDo(newTodo);
источник
bind(this)
во время передачи функции, это не вызывало ошибки такой функцииthis.setState is not a function
.Для тех, кто поддерживает состояние с помощью React Hook
useState
, я адаптировал приведенные выше предложения, чтобы создать демонстрационное приложение-слайдер ниже. В демонстрационном приложении компонент дочернего слайдера поддерживает состояние родителя.В демо также используется
useEffect
хук. (и, что менее важно,useRef
крючок)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;
источник
useEffect
? Зачем нам нужно хранить данные как в родительском, так и в дочернем состоянии?parentSetState={(obj) => { this.setState(obj) }}
источник
Я нашел следующее рабочее и простое решение для передачи аргументов от дочернего компонента родительскому компоненту:
//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") ); }
Посмотрите на JSFIDDLE
источник
Если вы работаете с компонентом класса в качестве родителя, один очень простой способ передать setState дочернему элементу - передать его внутри функции стрелки. Это работает, поскольку он устанавливает поднятую среду, которую можно передавать:
class ClassComponent ... { modifyState = () =>{ this.setState({...}) } render(){ return <><ChildComponent parentStateModifier={modifyState} /></> } }
источник