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 项的数组,它维护在父元素的状态中。 我想访问父节点的状态并从 TodoFormhandleClick组件中添加一个新的 todo 项。 我的想法是在父节点上执行 setState,它将呈现新添加的 todo 项。

141001 次浏览

您可以在父组件中创建一个 addTodo 函数,将其绑定到该上下文,将其传递给子组件并从那里调用它。

// in Todos
addTodo: function(newTodo) {
// add todo
}

然后,在 Todos.render,你会做

<TodoForm addToDo={this.addTodo.bind(this)} />

在 TodoForm 中用

this.props.addToDo(newTodo);

在父级中,您可以创建一个类似于 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: ""});
},


...


});

您可以在 TodoForm 的 handleClick 中调用 addTodoItem。这将在父节点上执行 setState,该节点将呈现新添加的 todo 项。希望你能明白。

小提琴。

I found the following working and simple solution to pass arguments from a child component to the parent component:

//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

这些基本上都是正确的,我只是想指出新的官方反应文件,它基本上建议:-

对于 React 应用程序中发生变化的任何数据,都应该有一个单一的“真相来源”。通常,首先将状态添加到呈现所需的组件中。然后,如果其他组件也需要它,你可以把它提升到它们最接近的共同祖先。您应该依赖自顶向下的数据流,而不是尝试在不同组件之间同步状态。

参见 https://reactjs.org/docs/lifting-state-up.html。该页面还通过一个示例进行工作。

parentSetState={(obj) => this.setState(obj)}

对于那些谁是保持与反作用钩 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;

如果使用类组件作为父组件,将 setState 传递给子组件的一种非常简单的方法是在箭头函数中传递它。它的工作原理是设置一个可以传递的悬挂环境:

class ClassComponent ... {


modifyState = () =>{
this.setState({...})
}
render(){
return <><ChildComponent parentStateModifier={modifyState} /></>
}
}

对于任何在 Arrow Functional Components中使用启用了 TypeScriptuseState的人来说,这里有一个简单的例子,说明如何将父级的 state setter 函数传递给子级,并调用它来在适当的时候从子级设置父级的状态-

Sample

家长组成部分:

import {useState} from "react";
const ParentComponent = () => {
const [hasParentStateChange, setHasParentStateChange] = useState<boolean>(false);


return (
<div>
Parent's view: {String(hasParentStateChange)}
<ChildComponent
hasParentStateChange={hasParentStateChange}
setHasParentStateChange={setHasParentStateChange} // <---- Passing parent's state setter over
/>
</div>
);
}

儿童部分:

interface PropsDefinition {
hasParentStateChange: boolean;
setHasParentStateChange(data: boolean): void;
}


const ChildComponent = (props: PropsDefinition) => {
return (
<div>
<div>
Child's view: {String(props.hasParentStateChange)}
</div>
<button
onClick={() => props.setHasParentStateChange(!props.hasParentStateChange)} // <---- Invoking parent's state setter
>
Toggle parent state from child
</button>
</div>
);
}