如何通过父组件访问和更改孩子的状态

时间:2020-09-03 15:19:54

标签: javascript reactjs typescript react-native

您将获得不可控制的子组件。 父组件存储计数器数量,并渲染该数量的子组件。它有两个按钮,“添加计数器”和“增加所有计数器”。

  1. 不允许您编辑子组件。

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

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

2 个答案:

答案 0 :(得分:0)

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

对于裁判,我无法提出一个好的解决方案(不确定)。 因此,我在这里传递了代码,然后做的是,我使用了一个名为 function addItems() { var newItems = [createNewRowData(), createNewRowData(), createNewRowData()]; var res = gridOptions.api.applyTransaction({ add: newItems }); printResult(res); } function printResult(res) { console.log('---------------------------------------'); if (res.add) { res.add.forEach(function(rowNode) { console.log('Added Row Node', rowNode); }); } if (res.remove) { res.remove.forEach(function(rowNode) { console.log('Removed Row Node', rowNode); }); } if (res.update) { res.update.forEach(function(rowNode) { console.log('Updated Row Node', rowNode); }); } } 的react钩子,使您的子组件使用ref并公开了内部useImperativeHandle方法。 然后我在您的父组件中添加了一组引用。 因此,当用户单击“全部增量”时,基本上可以遍历引用并调用内部增量方法。 我仍然不确定实现引用数组的正确方法,但是我认为应该这样做。 而且我已经用钩子编写了它,以使其更易于理解。

increment

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

答案 1 :(得分:0)

这是在技术上可能的,无需更改父级的ref即可更改子级,并且让父级每次使用ref来访问子级上的increment方法incrementAll被称为:

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>

但这很奇怪。对于实际问题,我建议使用lifting state up