ReactJS: setState на родительском внутреннем дочернем компоненте
Каков рекомендуемый шаблон для создания 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-элементов, который поддерживается в родительском состоянии.
Я хочу получить доступ к родительскому состоянию и добавить новый элемент todo из компонента TodoForm
handleClick
.
Моя идея состоит в том, чтобы сделать setState для родителя, который будет отображать новый добавленный элемент todo.
Ответы
Ответ 1
В своем родителе вы можете создать такую функцию, как addTodoItem
, которая будет выполнять требуемый setState, а затем передать эту функцию в качестве реквизита дочернего компонента.
var Todos = React.createClass({
...
addTodoItem: function(todoItem) {
this.state.todos.push(todoItem);
this.setState({todos: this.state.todos});
},
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
в методе TodoForm handleClick. Это будет делать setState для родителя, который будет отображать новый добавленный элемент todo. Надеюсь, вы поняли эту идею.
Заклинание здесь.
Ответ 2
Все они в основном правильные, я просто подумал, что укажу на новую (ish) официальную документацию по реагированию, которая в основном рекомендует: -
Должен быть единый "источник правды" для любых данных, которые изменяются в приложении React. Обычно состояние сначала добавляется к компоненту, который нуждается в нем для рендеринга. Затем, если другие компоненты также нуждаются в этом, вы можете поднять его до своего ближайшего общего предка. Вместо того, чтобы пытаться синхронизировать состояние между различными компонентами, вы должны полагаться на нисходящий поток данных.
Смотрите https://reactjs.org/docs/lifting-state-up.html. Страница также работает через пример.
Ответ 3
Вы можете создать функцию addTodo в родительском компоненте, привязать ее к этому контексту, передать его дочернему компоненту и вызвать его оттуда.
// in Todos
addTodo: function(newTodo) {
// add todo
}
Затем, в Todos.render, вы сделали бы
<TodoForm addToDo={this.addTodo.bind(this)} />
Позвоните в TodoForm с помощью
this.props.addToDo(newTodo);
Ответ 4
Я нашел следующее рабочее и простое решение для передачи аргументов из дочернего компонента в родительский компонент:
//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
Ответ 5
parentSetState={(obj) => { this.setState(obj) }}
Ответ 6
Для тех, кто поддерживает состояние с помощью React Hook useState
, я адаптировал приведенные выше предложения, чтобы создать приложение для демонстрационного слайдера ниже. В демонстрационном приложении дочерний компонент-слайдер поддерживает родительское состояние.
Демо также использует хук useEffect
. (и, что менее важно, useRef
хук)
import React, { useState, useEffect, 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 = val => {
setParentState(val);
};
return (
<div style={{ margin: 30 }}>
<Child
parentState={parentState}
parentStateSetter={wrapperSetParentState}
/>
<div>Parent State: {parentState}</div>
</div>
);
};
//the child react component
function Child(props) {
const childRef = useRef();
const [childState, setChildState] = useState(0);
useEffect(() => {
props.parentStateSetter(childState);
}, [childState]);
const onSliderChangeHandler = e => {
//pass slider event value to child 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;