首页 > 解决方案 > 如何从父组件访问和更改孩子的状态

问题描述

您将获得无法控制的子组件。父组件存储计数器的数量并呈现该数量的子组件。它有两个按钮添加计数器和增加所有计数器。

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

标签: javascriptreactjstypescriptreact-native

解决方案


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

使用 refs,我无法想出一个好的解决方案(不确定)。所以我在这里传递了代码,我所做的是,我使用了一个调用的 react 钩子useImperativeHandle来使您的子组件获取 ref 并公开内部increment方法。然后我在你的父组件中添加了一个引用数组。因此,当用户单击全部增量时,基本上您会遍历您的 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


推荐阅读