javascript - 如何从父组件访问和更改孩子的状态
问题描述
您将获得无法控制的子组件。父组件存储计数器的数量并呈现该数量的子组件。它有两个按钮添加计数器和增加所有计数器。
您不能编辑子组件。
实现 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>
)
}
}
解决方案
首先,我不知道为什么你不想用状态来做,我认为使用一组计数器值然后一次递增它们,并将你的子组件作为控制器组件会更好.
使用 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
推荐阅读
- php - 如何在 PHP 7.x 中自定义 Pretty_Printed JSON?
- typescript - 用于多个嵌套泛型的功能组合的 Typescript 等效项
- sql - 在 SQL 中填充具有相似值的列
- javascript - IOS 13.3 - 单击后退按钮时刷新页面
- mysql - 当我从转储 Mysql 中恢复时会发生什么
- sql - 在 SQL 中合并两个表,用一个公共列
- api - 通过 Ansible 一次 api 调用同时更新 100 个值
- c# - SeriLog Formatter:如何在json配置文件中传递formatter参数
- scala - Scala spark有什么办法可以将这个数据框转换成这个?
- sonarqube - SonarQube 7.9.1 LTS 未启动:无法创建共享内存