繁体   English   中英

如何从父组件访问和更改子组件的状态

[英]How to access and change child's state from Parent component

您将获得无法控制的子组件。 父组件存储计数器的数量并呈现该数量的子组件。 它有两个按钮 Add counter 和 Increment all counters。

  1. 不允许编辑子组件。

  2. 实现 incrementCounters 以便它增加呈现的所有子组件的计数器。

    incrementCounters = () => { // TODO: 实现 };


export class ChildCounter extends React.Component{
    state = {
        counter: 0
    };

    increment = () => {
        this.setState(({ counter }) => ({
            counter: counter + 1
        }));
    };

    render() {
        return (
            <div>
                Counter: {this.state.counter}
                <button onClick={this.increment}>+</button>
            </div>
        );
    }
}

import {ChildCounter} from "./Child";


class App extends React.Component {

    state = {counters:1}


    addCounter = () => {
     let counterRn = this.state.counters + 1;
     this.setState({counters:counterRn})
    };

   incrementAll = () => {

   }

   render() {
   return (
       <div>
                { new Array(this.state.counters).fill(0).map((_, index) => {
                    return <ChildCounter key={index} />;
                })
                }
           <br/>
           <button style={{marginRight:10}} onClick={this.addCounter}>Add Counter</button>
           <button onClick={this.incrementAll}>Increment all counters</button>
       </div>
   )
   }
}

首先,我不知道为什么你不想用状态来做,我认为通过使用一组计数器值然后一次增加它们会更好,并将你的子组件作为控制器组件.

对于裁判,我无法想出一个好的解决方案(不确定)。 所以我在这里传递了代码,我所做的是,我使用了一个名为useImperativeHandle的 react 钩子来让您的子组件获取 ref 并公开内部increment方法。 然后我在你的父组件中添加了一组 refs。 因此,当用户单击全部增量时,基本上您会遍历引用并调用内部增量方法。 我仍然不确定实现 refs 数组的正确方法,但我认为应该这样做。 我已经用钩子写了这个,让它更容易理解。


import React, {
  useState,
  useEffect,
  createRef,
  forwardRef,
  useImperativeHandle
} from "react";

const ChildCounter = forwardRef((props, ref) => {
  const [counter, setCounter] = useState(0);

  const increment = () => {
    setCounter((c) => c + 1);
  };

  useImperativeHandle(ref, () => ({
    increment
  }));

  return (
    <div>
      Counter: {counter}
      <button onClick={increment}>+</button>
    </div>
  );
});

const App = () => {
  const [counters, setCounters] = useState(1);
  const [elRefs, setElRefs] = useState([]);

  const addCounter = () => {
    setCounters((c) => c + 1);
  };

  useEffect(() => {
    setElRefs((elRefs) =>
      Array(counters)
        .fill()
        .map((_, i) => elRefs[i] || createRef())
    );
  }, [counters]);

  const incrementAll = () => {
    for (let i = 0; i < elRefs.length; i++) {
      if (elRefs[i] && elRefs[i].current) {
        elRefs[i].current.increment();
      }
    }
  };

  return (
    <div>
      {new Array(counters).fill(0).map((_, index) => {
        return <ChildCounter ref={elRefs[index]} key={index} />;
      })}
      <br />
      <button style={{ marginRight: 10 }} onClick={addCounter}>
        Add Counter
      </button>
      <button onClick={incrementAll}>Increment all counters</button>
    </div>
  );
};

export default App;

https://codesandbox.io/s/trusting-neumann-37e2q?file=/src/App.js:0-1327

这在技术上可以实现的,而无需通过从父级传递 ref 来更改子级,并且在调用incrementAll时让父级使用 ref 访问子级上的increment方法:

childCounterChildren = [];

incrementAll = () => {
    for (const counter of this.childCounterChildren) {
        counter.increment();
    }
}
<ChildCounter
    key={index}
    ref={(childCounter) => { if (childCounter) { this.childCounterChildren.push(childCounter); }}}
/>;

 class ChildCounter extends React.Component { state = { counter: 0 }; increment = () => { this.setState(({ counter }) => ({ counter: counter + 1 })); }; render() { return ( <div> Counter: {this.state.counter} <button onClick={this.increment}>+</button> </div> ); } } class App extends React.Component { state = { counters: 1 } childCounterChildren = []; addCounter = () => { let counterRn = this.state.counters + 1; this.setState({ counters: counterRn }) }; incrementAll = () => { for (const counter of this.childCounterChildren) { counter.increment(); } } componentWillUpdate() { this.childCounterChildren.length = 0; } render() { return ( <div> {new Array(this.state.counters).fill(0).map((_, index) => { return <ChildCounter key={index} ref={(childCounter) => { if (childCounter) { this.childCounterChildren.push(childCounter); }}} />; }) } <br /> <button style={{ marginRight: 10 }} onClick={this.addCounter}>Add Counter</button> <button onClick={this.incrementAll}>Increment all counters</button> </div> ) } } ReactDOM.render(<App />, document.querySelector('.react'));
 <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <div class='react'></div>

但这很奇怪。 对于实际问题,我建议改为提升状态

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM