ChatGPT解决这个技术问题 Extra ChatGPT

如何在 React 中更新父母的状态?

我的结构如下所示:

Component 1

 - |- Component 2


 - - |- Component 4


 - - -  |- Component 5

Component 3

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

由于 props 是不可变的,我不能简单地将其状态保存在 Component 1 中并转发它,对吗?是的,我已经阅读了 Redux,但我不想使用它。我希望可以通过反应来解决它。我错了吗?

超级简单:通过属性将 parent-setState-Function 传递给子组件: {this.setState(p)}} /> 在子组件中通过 this.props 调用它。 setState({myObj,...});
<MyChildComponent setState={(s,c)=>{this.setState(s, c)}} /> 如果您要使用此 hack,请确保您支持回调。
传递回调来设置父级的状态是一种非常糟糕的做法,可能会导致维护问题。它打破了封装,使组件 2 4 和 5 紧密耦合到 1。如果走这条路,那么您将无法在其他地方重用这些子组件中的任何一个。最好有特定的道具,这样子组件可以在发生任何事情时触发事件,然后父组件会正确处理该事件。
@MarcelEnnix,为什么 this.setState(p) 周围有大括号?我在没有它们的情况下尝试过,它似乎可以工作(我对 React 很陌生)
@Biganon 嗯。你说的对。对不起,额外的 2 个字符 :-) 也许是因为我非常喜欢花括号。我有一件印有此声明的衬衫^^

c
crg

对于子-父通信,您应该传递一个设置从父到子的状态的函数,像这样


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

这样,孩子可以通过调用道具传递的函数来更新父母的状态。

但是您将不得不重新考虑组件的结构,因为据我了解,组件 5 和 3 不相关。

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


为什么你需要 this.handler = this.handler.bind(this) 而不仅仅是设置状态的处理函数?
ES6 React 类方法中的 @chemook78 不会自动绑定到类。因此,如果我们不在构造函数中添加 this.handler = this.handler.bind(this),则 handler 函数内的 this 将引用函数闭包,而不是类。如果不想在构造函数中绑定所有函数,还有另外两种方法可以使用箭头函数来处理这个问题。您可以将点击处理程序编写为 onClick={()=> this.setState(...)},或者您可以将属性初始化程序与箭头函数一起使用,如此处 babeljs.io/blog/2015/06/07/react-on-es6-plus 在“箭头函数”下所述
下面是一个实际的例子:plnkr.co/edit/tGWecotmktae8zjS5yEr?p=preview
这一切都说得通,为什么要 e.preventDefault ?这需要jquery吗?
快速提问,这是否不允许在孩子中分配当地状态?
M
Mdev

这是使用新的 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>
  )
}

很好的现代例子
谢谢。 @mylesthe.dev
出于某种奇怪的原因。,我得到 stateChanger (setState) 不是一个函数。我使用了相同的确切代码
您传递给 stateChanger 的道具不是函数。或者你做错了什么。分享你的代码。
欢迎@MichaelWegter
P
Peter Mortensen

我找到了以下工作解决方案,将 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")
    );
}

Look at 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")
    );
}

Look at JSFiddle


这个不错!你能解释一下这件作品吗:<ChildB handleToUpdate = {handleToUpdate.bind(this)} />为什么要再次绑定?
@Dane-您必须将 this 的上下文绑定为父级,以便在子级内部调用 this 时, this 指的是父级的状态而不是子级的状态。这是最好的关闭!
@Casey,但我们不是在构造函数中这样做吗?这还不够吗??
你完全正确!我错过了。是的,如果您已经在构造函数中完成了它,那么您就可以开始了!
你是传说中的伙伴!这将保持组件很好地自包含,而不必被迫创建父组件来处理状态交换
A
Ardhi

我要感谢最受好评的答案,因为它让我了解了我自己的问题,基本上是它与箭头函数的变化并从子组件传递参数:

 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')}/ >
  }
}

希望它可以帮助某人。


与直接调用相比,箭头函数有什么特别之处?
@AshishKamble 箭头函数中的 this 指的是父级的上下文(即 Parent 类)。
这是一个重复的答案。您可以在已接受的答案中添加评论,并提及此实验功能以在课堂上使用箭头功能。
什么是(是)最受好评的答案?你可以说得更详细点吗?最受好评的答案可能会随着时间而改变。
P
Peter Mortensen

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

另一方面,您也可以像 Flux 那样使用 pub/sub 或使用变体调度程序来实现此目的。理论超级简单。让组件 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 或其他版本)。


我的 Reacts 组件在浏览器中“运行”,就像在官方教程 (facebook.github.io/react/docs/tutorial.html) 中一样
我使用的语法是需要转译的 ES2016 模块语法(我使用 Babel,但还有其他的,babelify 转换可以与 browserify 一起使用),它转译为 var Dispatcher = require( 'flux' ).Dispatcher
P
Peter Mortensen

我找到了以下工作解决方案,将 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>
    )
} }

谁能说出这是否是一个可接受的解决方案(特别有兴趣按照建议传递参数)。
param1 只是显示在控制台上而不是分配它总是分配 true
我无法谈论解决方案的质量,但这成功地为我传递了参数。
P
Peter Mortensen

每当您需要在任何级别的孩子与父母之间进行交流时,最好利用上下文。在父组件中定义可以被子组件调用的上下文,例如:

在父组件中,在您的案例组件 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>
)}

您可以在 this GitHub repository 中找到演示项目。


我无法理解这个答案,你能解释一下吗
P
Peter Mortensen

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

我们将父级中定义的函数作为“道具”传递给子级,并从子级调用该函数,在父组件中触发它。

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>

在此示例中,我们可以通过将函数传递给其直接子项来使数据从子子→子→父传递。


P
Peter Mortensen

之前给出的大多数答案都是针对基于 React.Component 的设计。如果您在最近的 React 库升级中使用 useState,请遵循 this answer


P
Peter Mortensen

我已经多次使用此页面中评价最高的答案,但是在学习 React 时,我找到了一种更好的方法来做到这一点,无需绑定,也无需在 props 中使用内联函数。

看看这里:

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})
}

您可以阅读更多here


P
Peter Mortensen

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

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 库进行 props 类型检查。

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;

当孩子的孩子影响其父母的道具时,这是如何工作的?
P
Peter Mortensen

如果要更新父组件,

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 是一个属性,其实例绑定了“处理程序”方法。我们将方法处理程序传递给 Child 类组件,以通过其 props 参数中的 onChange 属性接收。

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

props = {
    onChange: this.handler
}

并传递给子组件。

所以子组件可以像这个props.onChange一样访问props对象中name的值。

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

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

参考和出处: Bits and Pieces


抱歉.. 延迟,这里的 onChange 是一个属性,它的实例绑定了“处理程序”方法。我们将方法处理程序传递给 Child 类组件,以通过其 props 参数中的 onChange 属性接收。属性 onChange 将在 props 对象中设置,如下所示: props ={ onChange : this.handler } 并传递给子组件因此子组件可以像这样访问 props 对象中 name 的值 props.onChange 它是通过渲染道具的使用。 参考资料和出处: [blog.bitsrc.io/…
P
Peter Mortensen

如果同样的场景没有在任何地方传播,你可以使用 React 的上下文,特别是如果你不想引入状态管理库引入的所有开销。另外,它更容易学习。但小心点;你可能会过度使用它并开始编写糟糕的代码。基本上,您定义了一个 Container 组件(它将为您保存并保留该状态),使所有组件都对向/从其子级(不一定是直接子级)写入/读取该数据块感兴趣。

Context - React

你也可以正确地使用一个普通的 React。

<Component5 onSomethingHappenedIn5={this.props.doSomethingAbout5} />

将 doSomethingAbout5 传递给组件 1:

<Component1>
    <Component2 onSomethingHappenedIn5={somethingAbout5 => this.setState({somethingAbout5})}/>
    <Component5 propThatDependsOn5={this.state.somethingAbout5}/>
<Component1/>

如果这是一个常见问题,您应该开始考虑将应用程序的整个状态转移到其他地方。您有几个选择,最常见的是:

还原

通量

基本上,不是在组件中管理应用程序状态,而是在发生某些事情时发送命令来更新状态。组件也从这个容器中提取状态,因此所有数据都是集中的。这并不意味着您不能再使用本地状态,但这是一个更高级的主题。


P
Peter Mortensen

我们可以通过将函数作为 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>
         )
     }
}

这样,孩子将更新父状态 onInputChange 和 onFormSubmit 是从父母传递的道具。这可以从子事件侦听器中调用,因此状态将在那里更新。


c
crg

这是一个简短的片段,用于获取两种绑定数据的方式。

计数器显示来自父级的值并从子级更新

class Parent 扩展 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 } } class Child extends React.Component { render() { return } } ReactDOM.render(, document.getElementById("root"));


P
Peter Mortensen

这就是我这样做的方式:

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

这里的想法是什么?有人可以详细说明吗?
P
Peter Mortensen

根据您的问题,我了解您需要在组件 3 中显示一些基于组件 5 状态的条件数据。方法:

组件 3 的状态将保存一个变量来检查组件 5 的状态是否具有该数据 一个箭头函数将更改组件 3 的状态变量。使用 props 将箭头函数传递给组件 5。组件 5 有一个箭头函数,它将改变组件 3 的状态变量 组件 5 的箭头函数在加载自身时调用

Class Component3 extends React.Component { state = { someData = true } checkForData = (result) => { this.setState({someData : result}) } render() { if(this.state.someData) { return( //其他数据); } else { return( //其他数据 ); } } } 导出默认组件3;类 Component5 扩展 React.Component { state = { dataValue = "XYZ" } checkForData = () => { if(this.state.dataValue === "XYZ") { this.props.hasData(true); } 其他 { this.props.hasData(false); } } render() { return(

//条件数据
); } } 导出默认组件 5;


B
Basir Payenda

只需通过 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;

a
ali orooji

要在孩子中设置父母的状态,您可以使用回调。

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 似乎是兄弟。所以你有3个选择:

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

2- 一起使用 useContext 和 useRducer(或 useState)。

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


a
atazmin

这似乎对我有用

家长:

...

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>

S
Salma Gomaa

您可以通过将父级的引用传递给子级来做到这一点,如下所示:

在 A.js 中使用方法 updateAState 在 A.js 中具有父组件 A 在 B.js 中具有子组件 B 在 C.js 中呈现 的包装器函数 在 C.js 中您可以使用 useRef 如下:

导入反应,{ useRef } 从“反应”;导出默认函数 C() { const parentARef = useRef(); const handleChildBClick = () => parentARef.current.updateAState();返回( ); }

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


A
Anmol Shrivastav

父组件

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

s
suresh
<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.

它会导致性能问题:stackoverflow.com/q/36677733/3328979