React js从父组件更改子组件的状态

Posted

技术标签:

【中文标题】React js从父组件更改子组件的状态【英文标题】:React js change child component's state from parent component 【发布时间】:2016-12-26 18:32:09 【问题描述】:

我有两个组件: 我要更改子组件状态的父组件

class ParentComponent extends Component 
  toggleChildMenu() 
    ?????????
  
  render() 
    return (
      <div>
        <button onClick=toggleChildMenu.bind(this)>
          Toggle Menu from Parent
        </button>
        <ChildComponent />
      </div>
    );
  

子组件

class ChildComponent extends Component 
  constructor(props) 
    super(props);
    this.state = 
      open: false;
    
  

  toggleMenu() 
    this.setState(
      open: !this.state.open
    );
  

  render() 
    return (
      <Drawer open=this.state.open/>
    );
  

我需要在父组件中更改子组件的open状态,或者在单击父组件中的按钮时从父组件调用子组件的toggleMenu()? p>

【问题讨论】:

也许你可以在父母中持有一个孩子的引用,并明确改变孩子的状态,见doc 【参考方案1】:

状态应该在父组件中管理。您可以通过添加属性将open 值传递给子组件。

class ParentComponent extends Component 
   constructor(props) 
      super(props);
      this.state = 
        open: false
      ;

      this.toggleChildMenu = this.toggleChildMenu.bind(this);
   

   toggleChildMenu() 
      this.setState(state => (
        open: !state.open
      ));
   

   render() 
      return (
         <div>
           <button onClick=this.toggleChildMenu>
              Toggle Menu from Parent
           </button>
           <ChildComponent open=this.state.open />
         </div>
       );
    


class ChildComponent extends Component 
    render() 
      return (
         <Drawer open=this.props.open/>
      );
    

【讨论】:

是的,这基本上就是 react-classnames 包所做的,但它也允许您始终应用一组类名,并有条件地应用其他类名。像这样:classNames( foo: true, bar: this.props.open ); // => 'foo' 当 this.props.open = false 和 'foo bar' 当 this.props.open = true 时。 如何改变子组件的打开状态? 可以给子组件&lt;ChildComponent open=this.state.open toggle=this.toggleChildMenu.bind(this) /&gt;添加属性toggle,在子组件中调用this.props.toggle() 我不明白,只要在声明ChildComponent时指定了这个属性就可以在子组件中任意调用它-> &lt;ChildComponent toggle=this.toggleChildMenu.bind(this) /&gt; 通过这种方式,整个父组件正在重新渲染,从而降低了效率。你能告诉我只有子组件会更新其状态或道具(意味着重新渲染)而不重新渲染父组件的任何方式吗?【参考方案2】:

父组件可以管理子状态,将 prop 传递给子组件,子组件使用 componentWillReceiveProps 将此 prop 转换为状态。

class ParentComponent extends Component 
  state =  drawerOpen: false 
  toggleChildMenu = () => 
    this.setState( drawerOpen: !this.state.drawerOpen )
  
  render() 
    return (
      <div>
        <button onClick=this.toggleChildMenu>Toggle Menu from Parent</button>
        <ChildComponent drawerOpen=this.state.drawerOpen />
      </div>
    )
  


class ChildComponent extends Component 
  constructor(props) 
    super(props)
    this.state = 
      open: false
    
  

  componentWillReceiveProps(props) 
    this.setState( open: props.drawerOpen )
  

  toggleMenu() 
    this.setState(
      open: !this.state.open
    )
  

  render() 
    return <Drawer open=this.state.open />
  

【讨论】:

在反应 16 中使用 getDerivedStateFromProps @FadiAboMsalam 我正在使用带有 @Types/react 版本 16.7.18 的 react 版本 16.7.0。至少在 TypeScript 方面似乎没有getDerivedStateFromProps()。但是,Miguel 建议使用 componentWillReceiveProps(props) 的答案是可用的,并且在我的环境中就像一个魅力。 在这种情况下,子组件内部的 toggleMenu() 状态变化将如何到达父组件?想象一下我关闭了抽屉,父组件怎么知道它已经关闭了?【参考方案3】:

以上答案对我来说部分正确,但在我的场景中,我想将值设置为状态,因为我已使用该值来显示/切换模式。所以我像下面这样使用过。希望它会对某人有所帮助。

class Child extends React.Component 
  state = 
    visible:false
  ;

  handleCancel = (e) => 
      e.preventDefault();
      this.setState( visible: false );
  ;

  componentDidMount() 
    this.props.onRef(this)
  

  componentWillUnmount() 
    this.props.onRef(undefined)
  

  method() 
    this.setState( visible: true );
  

  render() 
    return (<Modal title="My title?" visible=this.state.visible onCancel=this.handleCancel>
      "Content"
    </Modal>)
  


class Parent extends React.Component 
  onClick = () => 
    this.child.method() // do stuff
  
  render() 
    return (
      <div>
        <Child onRef=ref => (this.child = ref) />
        <button onClick=this.onClick>Child.method()</button>
      </div>
    );
  

参考 - https://github.com/kriasoft/react-starter-kit/issues/909#issuecomment-252969542

【讨论】:

这就是我想要的,但我想知道为什么不直接使用 react refs?见doc onRef 属性有什么作用? 这实际上是 react 中不鼓励使用的模式,因为它会反转信息流。如果 react 有一个 Zen,它是 数据向下,动作向上。这就是让 React 应用程序如此易于推理的概念。命令式句柄可能很有用,但应谨慎使用且经过深思熟虑。它们不应该是例如的首选解决方案。切换可见性。【参考方案4】:

您可以使用createRef 从父组件更改子组件的状态。以下是所有步骤。

    创建一个方法来更改子组件中的状态。 使用React.createRef()为父组件中的子组件创建引用。 使用ref= 将引用附加到子组件。 使用this.yor-reference.current.method调用子组件方法。

父组件


class ParentComponent extends Component 
constructor()

this.changeChild=React.createRef()

  render() 
    return (
      <div>
        <button onClick=this.changeChild.current.toggleMenu()>
          Toggle Menu from Parent
        </button>
        <ChildComponent ref=this.changeChild />
      </div>
    );
  


子组件


class ChildComponent extends Component 
  constructor(props) 
    super(props);
    this.state = 
      open: false;
    
  

  toggleMenu=() => 
    this.setState(
      open: !this.state.open
    );
  

  render() 
    return (
      <Drawer open=this.state.open/>
    );
  




【讨论】:

这是我找到的最佳答案,因为它不会重新渲染父组件。这是更快更好的做法! 是的,这实际上也是满足我需求的最佳答案。这很干净,我们应该赞成这个答案。 在父级上,我不得不使用处理程序方法而不是直接调用子级。然后它起作用了。【参考方案5】:

您可以从父组件发送一个 prop 并在子组件中使用它,这样您就可以根据发送的 prop 更改来更改子组件的状态,您可以在子组件中使用 getDerivedStateFromProps 来处理这个问题。

【讨论】:

【参考方案6】:

如果您使用的是功能组件。您可以通过以下方式实现:

const ParentComponent = () => 
   const [isOpen, setIsOpen] = useState(false)

   toggleChildMenu() 
      setIsOpen(prevValue => !prevValue)
   

   return (
     <div>
       <button onClick=toggleChildMenu>
         Toggle Menu from Parent
       </button>
       <Child open=isOpen />
     </div>
   );




const Child = (open) => 
  return (
    <Drawer open=open/>
  );

【讨论】:

以上是关于React js从父组件更改子组件的状态的主要内容,如果未能解决你的问题,请参考以下文章

React 子组件不会在其状态更改时重新渲染

在 React.js 的父组件中使用 react-router 时,如何使用 react context API 将数据从父组件传递到子组件?

React Native - 从父组件重新渲染子组件

从父 React 刷新子状态

React:将状态传递给子组件

如何在 react.js 中跨子组件持久化数据或状态?