[英]How to access and change child's state from Parent component
您将获得无法控制的子组件。 父组件存储计数器的数量并呈现该数量的子组件。 它有两个按钮 Add counter 和 Increment all counters。
不允许编辑子组件。
实现 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.