我如何更新父母's状态在反应?

我的结构如下所示:

Component 1


- |- Component 2




- - |- Component 4




- - -  |- Component 5


Component 3

组件3应该根据组件5的状态显示一些数据。

因为道具是不可变的,我不能简单地在组件1中保存它的状态并转发它,对吗?是的,我读过回来的,但我不想用它。我希望只用react就能解决这个问题。我错了吗?

562011 次浏览

对于子-父通信,您应该传递一个函数来设置从父到子的状态,如下所示


class Parent extends React.Component {
constructor(props) {
super(props)


this.handler = this.handler.bind(this)
}


handler() {
this.setState({
someVar: 'some value'
})
}


render() {
return <Child handler = {this.handler} />
}
}


class Child extends React.Component {
render() {
return <Button onClick = {this.props.handler}/ >
}
}


这样,子进程就可以通过调用带有props的函数来更新父进程的状态。

但是你必须重新考虑组件的结构,因为根据我的理解,组件5和组件3是不相关的。

一种可能的解决方案是将它们包装在一个更高级别的组件中,该组件将同时包含组件1和组件3的状态。该组件将通过props设置较低级别的状态。

我喜欢关于传递函数的答案。这是一个非常方便的技巧。

另一方面,您也可以使用发布/订阅或使用变体,如通量所做的调度程序来实现这一点。理论非常简单。让组件5发送一个组件3正在监听的消息。然后组件3更新它的状态,从而触发重新呈现。这需要有状态的组件,根据您的观点,这些组件可能是反模式,也可能不是。我个人反对这种方法,我更希望有其他的方法能够从自上而下监听分派和更改状态(Redux做到了这一点,但它增加了额外的术语)。

import { Dispatcher } from 'flux'
import { Component } from 'React'


const dispatcher = new Dispatcher()


// Component 3
// Some methods, such as constructor, omitted for brevity
class StatefulParent extends Component {
state = {
text: 'foo'
}


componentDidMount() {
dispatcher.register( dispatch => {
if ( dispatch.type === 'change' ) {
this.setState({ text: 'bar' })
}
}
}


render() {
return <h1>{ this.state.text }</h1>
}
}


// Click handler
const onClick = event => {
dispatcher.dispatch({
type: 'change'
})
}


// Component 5 in your example
const StatelessChild = props => {
return <button onClick={ onClick }>Click me</button>
}

使用Flux的调度程序捆绑非常简单。它只是简单地注册回调,并在任何分派发生时调用它们,传递分派上的内容(在上面的简洁示例中,分派中没有payload,只有一个消息id)。如果对您更有意义的话,您可以很容易地将其调整为传统的pub/sub(例如,从事件中使用EventEmitter或其他版本)。

当您需要在子进程和父进程之间进行任何级别的通信时,最好使用上下文。在父组件中定义可以被子组件调用的上下文,例如:

在父组件中,在你的案例中,组件3,

static childContextTypes = {
parentMethod: React.PropTypes.func.isRequired
};


getChildContext() {
return {
parentMethod: (parameter_from_child) => this.parentMethod(parameter_from_child)
};
}


parentMethod(parameter_from_child){
// Update the state with parameter_from_child
}

现在在子组件中(在你的例子中是组件5),只需告诉这个组件它想要使用它的父组件的上下文。

static contextTypes = {
parentMethod: React.PropTypes.func.isRequired
};


render() {
return(
<TouchableHighlight
onPress = {() => this.context.parentMethod(new_state_value)}
underlayColor='gray' >


<Text> update state in parent component </Text>


</TouchableHighlight>
)}

您可以在这个GitHub存储库中找到演示项目。

我找到了以下工作解决方案,将onClick函数参数从子组件传递给父组件:

传递方法()的版本

//ChildB component
class ChildB extends React.Component {


render() {


var handleToUpdate = this.props.handleToUpdate;
return (<div><button onClick={() => handleToUpdate('someVar')}>
Push me
</button>
</div>)
}
}


//ParentA component
class ParentA extends React.Component {


constructor(props) {
super(props);
var handleToUpdate = this.handleToUpdate.bind(this);
var arg1 = '';
}


handleToUpdate(someArg){
alert('We pass argument from Child to Parent: ' + someArg);
this.setState({arg1:someArg});
}


render() {
var handleToUpdate = this.handleToUpdate;


return (<div>
<ChildB handleToUpdate = {handleToUpdate.bind(this)} /></div>)
}
}


if(document.querySelector("#demo")){
ReactDOM.render(
<ParentA />,
document.querySelector("#demo")
);
}

看JSFiddle

使用传递箭头函数的版本

//ChildB component
class ChildB extends React.Component {


render() {


var handleToUpdate = this.props.handleToUpdate;
return (<div>
<button onClick={() => handleToUpdate('someVar')}>
Push me
</button>
</div>)
}
}


//ParentA component
class ParentA extends React.Component {
constructor(props) {
super(props);
}


handleToUpdate = (someArg) => {
alert('We pass argument from Child to Parent: ' + someArg);
}


render() {
return (<div>
<ChildB handleToUpdate = {this.handleToUpdate} /></div>)
}
}


if(document.querySelector("#demo")){
ReactDOM.render(
<ParentA />,
document.querySelector("#demo")
);
}

看JSFiddle

我找到了以下工作解决方案,将onClick函数参数从子组件传递给带有参数的父组件:

父类:

class Parent extends React.Component {
constructor(props) {
super(props)


// Bind the this context to the handler function
this.handler = this.handler.bind(this);


// Set some state
this.state = {
messageShown: false
};
}


// This method will be sent to the child component
handler(param1) {
console.log(param1);
this.setState({
messageShown: true
});
}


// Render the child component and set the action property with the handler as value
render() {
return <Child action={this.handler} />
}}

子类:

class Child extends React.Component {
render() {
return (
<div>
{/* The button will execute the handler function set by the parent component */}
<Button onClick={this.props.action.bind(this,param1)} />
</div>
)
} }
<Footer
action={()=>this.setState({showChart: true})}
/>


<footer className="row">
<button type="button" onClick={this.props.action}>Edit</button>
{console.log(this.props)}
</footer>


Try this example to write inline setState, it avoids creating another function.

我们可以创建ParentComponent并使用handleInputChange方法来更新ParentComponent的状态。导入ChildComponent并将两个道具从父组件传递给子组件,即handleInputChange函数和count。

import React, { Component } from 'react';
import ChildComponent from './ChildComponent';


class ParentComponent extends Component {
constructor(props) {
super(props);
this.handleInputChange = this.handleInputChange.bind(this);
this.state = {
count: '',
};
}


handleInputChange(e) {
const { value, name } = e.target;
this.setState({ [name]: value });
}


render() {
const { count } = this.state;
return (
<ChildComponent count={count} handleInputChange={this.handleInputChange} />
);
}
}

现在我们创建了ChildComponent文件,并将其保存为ChildComponent.jsx。这个组件是无状态的,因为子组件没有状态。我们使用prop-types库进行道具类型检查。

import React from 'react';
import { func, number } from 'prop-types';


const ChildComponent = ({ handleInputChange, count }) => (
<input onChange={handleInputChange} value={count} name="count" />
);


ChildComponent.propTypes = {
count: number,
handleInputChange: func.isRequired,
};


ChildComponent.defaultProps = {
count: 0,
};


export default ChildComponent;

我想感谢得到最多赞的回答,因为他给了我自己的问题的想法,基本上是用箭头函数和从子组件传递参数的变化:

 class Parent extends React.Component {
constructor(props) {
super(props)
// without bind, replaced by arrow func below
}


handler = (val) => {
this.setState({
someVar: val
})
}


render() {
return <Child handler = {this.handler} />
}
}


class Child extends React.Component {
render() {
return <Button onClick = {() => this.props.handler('the passing value')}/ >
}
}

希望它能帮助到别人。

似乎我们只能在React启动单向数据流时将数据从父组件传递给子组件,但是为了让父组件在“子组件”中发生事情时更新自己,我们通常使用所谓的“回调函数”。

将父类中定义的函数作为" props"传递给子类而且 从子进程调用该函数,在父进程中触发它 组件。< / p >

class Parent extends React.Component {
handler = (Value_Passed_From_SubChild) => {
console.log("Parent got triggered when a grandchild button was clicked");
console.log("Parent->Child->SubChild");
console.log(Value_Passed_From_SubChild);
}
render() {
return <Child handler = {this.handler} />
}
}


class Child extends React.Component {
render() {
return <SubChild handler = {this.props.handler}/ >
}
}


class SubChild extends React.Component {
constructor(props){
super(props);
this.state = {
somethingImp : [1,2,3,4]
}
}
render() {
return <button onClick = {this.props.handler(this.state.somethingImp)}>Clickme<button/>
}
}
React.render(<Parent />,document.getElementById('app'));


HTML
----
<div id="app"></div>

在这个例子中,我们可以将数据从子的孩子孩子传递给函数的直接子函数。

我已经多次使用这个页面的顶级答案,但在学习React的时候,我发现了一个更好的方法,没有绑定,也没有道具内的内联函数。

看看这里:

class Parent extends React.Component {


constructor() {
super();
this.state = {
someVar: value
}
}


handleChange = (someValue) => {
this.setState({someVar: someValue})
}


render() {
return <Child handler={this.handleChange} />
}


}


export const Child = ({handler}) => {
return <Button onClick={handler} />
}

键在一个箭头函数中:

handleChange = (someValue) => {
this.setState({someVar: someValue})
}

你可以阅读更多在这里

如果你想要更新父组件,

class ParentComponent extends React.Component {
constructor(props){
super(props);
this.state = {
page: 0
}
}


handler(val){
console.log(val) // 1
}


render(){
return (
<ChildComponent onChange={this.handler} />
)
}
}




class ChildComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
page: 1
};
}


someMethod = (page) => {
this.setState({ page: page });
this.props.onChange(page)
}


render() {
return (
<Button
onClick={() => this.someMethod()}
> Click
</Button>
)
}
}

这里的onChange是一个带有“handler”的属性;方法绑定到其实例。我们将方法处理程序传递给子类组件,通过props参数中的onChange属性接收。

onChange属性将在props对象中设置,如下所示:

props = {
onChange: this.handler
}

并传递给子组件。

因此,孩子组件可以像props.onChange一样访问props对象中的name值。

这是通过使用渲染道具完成的。

现在孩子组件有一个按钮“Click”,带有一个onclick事件集,用于调用通过props参数对象中的onChange传递给它的处理程序方法。所以现在子类中的this.props.onChange保存了类中的输出方法。

# EYZ0 # EYZ1

我是这样做的:

type ParentProps = {}
type ParentState = { someValue: number }
class Parent extends React.Component<ParentProps, ParentState> {
constructor(props: ParentProps) {
super(props)
this.state = { someValue: 0 }


this.handleChange = this.handleChange.bind(this)
}


handleChange(value: number) {
this.setState({...this.state, someValue: value})
}


render() {
return <div>
<Child changeFunction={this.handleChange} defaultValue={this.state.someValue} />
<p>Value: {this.state.someValue}</p>
</div>
}
}


type ChildProps = { defaultValue: number, changeFunction: (value: number) => void}
type ChildState = { anotherValue: number }
class Child extends React.Component<ChildProps, ChildState> {
constructor(props: ChildProps) {
super(props)
this.state = { anotherValue: this.props.defaultValue }


this.handleChange = this.handleChange.bind(this)
}


handleChange(value: number) {
this.setState({...this.state, anotherValue: value})
this.props.changeFunction(value)
}


render() {
return <div>
<input onChange={event => this.handleChange(Number(event.target.value))} type='number' value={this.state.anotherValue}/>
</div>
}
}

之前给出的大多数答案都是基于# eyz1的设计。如果你在最近的React库升级中使用了useState,那么请遵循这个答案

我们可以通过将一个函数作为props传递给子组件来设置子组件的父状态,如下所示:

class Parent extends React.Component{
state = { term : ''}


onInputChange = (event) => {
this.setState({term: event.target.value});
}


onFormSubmit = (event) => {
event.preventDefault();
this.props.onFormSubmit(this.state.term);
}


render(){
return (
<Child onInputChange={this.onInputChange} onFormSubmit=
{this.onFormSubmit} />
)
}
}




class Child extends React.Component{


render(){
return (
<div className="search-bar ui segment">
<form className="ui form" onSubmit={this.props.onFormSubmit}>
<div class="field">
<label>Search Video</label>
<input type="text" value={this.state.term} onChange=
{this.props.onInputChange} />
</div>
</form>
</div>
)
}
}

这样,子进程将更新父进程状态onInputChangeonFormSubmit是父进程传递过来的道具。这可以从子进程中的事件听众中调用,因此状态将在那里更新。

关于你的问题,我理解你需要在Component 3中显示一些基于Component 5状态的条件数据。方法:

  1. 组件3的状态将保存一个变量来检查组件5的状态是否有该数据
  2. 箭头功能,它将改变组件3的状态变量。
  3. 向组件5传递一个带有道具的箭头函数。
  4. 组件5有一个箭头函数,它将改变组件3的状态变量
  5. 组件5的箭头函数在加载自身时调用

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Class Component3 extends React.Component {
state = {
someData = true
}


checkForData = (result) => {
this.setState({someData : result})
}


render() {
if(this.state.someData) {
return(
<Component5 hasData = {this.checkForData} />
//Other Data
);
}
else {
return(
//Other Data
);
}
}
}


export default Component3;


class Component5 extends React.Component {
state = {
dataValue = "XYZ"
}
checkForData = () => {
if(this.state.dataValue === "XYZ") {
this.props.hasData(true);
}
else {
this.props.hasData(false);
}
}
render() {
return(
<div onLoad = {this.checkForData}>
//Conditional Data
</div>
);
}
}
export default Component5;

这是如何使用新的useState钩子。

方法-将状态改变器函数作为道具传递给子组件,并对该函数做任何你想做的事情:

import React, {useState} from 'react';


const ParentComponent = () => {
const[state, setState]=useState('');
  

return(
<ChildComponent stateChanger={setState} />
)
}




const ChildComponent = ({stateChanger, ...rest}) => {
return(
<button onClick={() => stateChanger('New data')}></button>
)
}

下面是获得两种绑定数据方式的简短代码片段。

计数器显示来自父进程的值,并从子进程更新

class Parent extends React.Component {
constructor(props) {
super(props)
this.handler = this.handler.bind(this)
this.state = {
count: 0
}
}


handler() {
this.setState({
count: this.state.count + 1
})
}


render() {
return <Child handler={this.handler} count={this.state.count} />
}
}


class Child extends React.Component {
render() {
return <button onClick={this.props.handler}>Count {this.props.count}</button>
}
}


ReactDOM.render(<Parent />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>


<div id="root"></div>

要设置子进程中父进程的状态,可以使用回调函数。

const Child = ({handleClick}) => (
<button on click={() => handleClick('some vale')}>change value</button>
)


const parent = () => {
const [value, setValue] = useState(null)


return <Child handleClick={setValue} />
}

在你的结构中,组件1和组件3似乎是兄弟。所以你有三个选择:

1-将状态放入它们的父级(不推荐4层父子级)。

2-同时使用useContext和useRducer(或useState)。

3-使用状态管理器,如redux, mobx…

只需通过props将父组件的setState函数传递给子组件。

function ParentComp() {
const [searchValue, setSearchValue] = useState("");
return <SearchBox setSearchValue={setSearchValue} searchValue={searchValue} />;
}

然后在子组件中:

function SearchBox({ searchValue, setSearchValue }) {
return (
<input
id="search-post"
type="text"
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
placeholder="Search Blogs ..."
/>
)
}

处理子组件点击的第二个例子:

// We've below function and component in parent component
const clickHandler = (val) => {
alert(`httpRequest sent. \nValue Received: ${val}`);
};


// JSX
<HttpRequest clickHandler={clickHandler} />

这就是你如何从父组件中获取函数,然后传递一个值并通过它触发clickHandler

function HttpRequest({ clickHandler }) {
const [content, setContent] = useState("initialState");


return (
<button onClick={() => clickHandler(content)}>
Send Request
</button>
);
}


export default HttpRequest;

这似乎对我有用

家长:

...

const [open, setOpen] = React.useState(false);


const handleDrawerClose = () => {
setOpen(false);
};

...

return (
<PrimaryNavigationAccordion
handleDrawerClose={handleDrawerClose}
/>
);

孩子:

...

export default function PrimaryNavigationAccordion({
props,
handleDrawerClose,
})

...

<Link
to={menuItem.url}
component={RouterLink}
color="inherit"
underline="hover"
onClick={() => handleDrawerClose()}
>
{menuItem.label}
</Link>

你可以通过将父对象的引用传递给子对象来实现,如下所示:

  1. 在A.js中使用方法updateAState的父组件a
  2. 在B.js中有一个子组件B
  3. 拥有一个在C.js中呈现<A><B></B></A>的包装器函数
  4. 在C.js中,你可以像下面这样使用useRef:
import React, { useRef } from "react";


export default function C()
{
const parentARef = useRef();
const handleChildBClick = () => parentARef.current.updateAState();
return (
<A ref={parentARef}>
<B onClick={handleChildBClick}>
</B>
</A>
);
}

指南参考:https://stackoverflow.com/a/56496607/1770571

父组件

 function Parent() {
const [value, setValue] = React.useState("");


function handleChange(newValue) {
setValue(newValue);
}


// We pass a callback to Child
return <Child value={value} onChange={handleChange} />;
}

子组件

    function Child(props) {
function handleChange(event) {
// Here, we invoke the callback with the new value
props.onChange(event.target.value);
}
  

return <input value={props.value} onChange={handleChange} />
}

在React中,数据不能从子节点传递到父节点。数据必须从父节点传递给子节点。在这种情况下,您可以使用内置的Context API或第三方状态管理解决方案,如Redux、Mobx或Apollo GraphQL。然而,如果你的应用程序结构太小,你可以将数据存储在你的父元素中,然后通过prop drilling将其发送给你的子元素。但如果你的项目比较大,就会很混乱。