[英]React parent couldn't update a child component in a mapped JSX list
NOTE: You can view and edit the code in CodeSandbox .注意:您可以在CodeSandbox中查看和编辑代码。
I have the following parent file which creates a useState
list of child component called ProgressBar
:我有以下父文件,它创建名为
ProgressBar
的子组件的useState
列表:
import React, { useState } from 'react';
import ProgressBar from './ProgressBar';
import './App.css';
var idCounter = 0;
export default function App() {
const [barsArray, setBarsArray] = useState([]);
const [input, setInput] = useState('');
function add() {
setBarsArray((prev) => [
...prev,
<ProgressBar key={idCounter++} restart={false} />,
]);
}
function remove() {
setBarsArray((prev) => prev.filter((bar) => bar.key !== input));
}
function reset() {
setBarsArray((prev) =>
prev.map((bar) => (bar.key === input ? { ...bar, restart: true } : bar))
);
}
return (
<div className='App'>
<div className='buttons'>
<button className='button-add' onClick={add}>
Add
</button>
<button className='button-delete' onClick={remove}>
Delete
</button>
<button className='button-delete' onClick={reset}>
Reset
</button>
<input
type='number'
value={input}
onInput={(e) => setInput(e.target.value)}
/>
</div>
<div className='bars-container'>
{barsArray.map((bar) => (
<div className='bars-index' key={bar.key}>
{bar}
<p>{bar.key}</p>
</div>
))}
</div>
</div>
);
}
The file of the child ProgressBar
has the following content:子
ProgressBar
的文件有以下内容:
import React, { useEffect, useState } from 'react';
import './ProgressBar.css';
export default function ProgressBar(props) {
const [progress, setProgress] = useState(0);
let interval;
useEffect(() => {
interval = setInterval(() => {
setProgress((prev) => prev + 1);
}, RnadInt(10, 120));
}, []);
useEffect(() => {
if (progress >= 100) clearInterval(interval);
}, [progress]);
if (props.restart === true) {
setProgress(0);
}
return (
<>
<div className='ProgressBarContainer'>
<div className='ProgressBar' style={{ width: progress + '%' }}></div>
</div>
</>
);
}
function RnadInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
My problem is that the reset button in the parent doesn't work, as far as I'm concerned, if you change the passed props to the child, the child automatically re-renders, but even though I'm updating the props in reset
function in the parent, which maps the old array of child components to a new array and only changes the props of the selected child.我的问题是父母中的重置按钮不起作用,就我而言,如果您将传递的道具更改为孩子,孩子会自动重新渲染,但即使我正在更新道具在 parent 中
reset
function,它将子组件的旧数组映射到新数组,并且只更改所选子组件的 props。
Thanks谢谢
Adding the element in state via add
would require to keep the ref of element instead of actual prop bind to element.通过
add
在 state 中添加元素需要保留元素的引用而不是实际的道具绑定到元素。 Suggestion here to use the model object and while rendering use the JSX element.此处建议使用 model object 并在渲染时使用 JSX 元素。
Please use the below code which defines the barsArray
as object state and later uses it render ProgressBar
component (from map call).请使用下面的代码将
barsArray
定义为 object state 并稍后使用它渲染ProgressBar
组件(来自 map 调用)。
Check the working codesandbox - https://codesandbox.io/s/admiring-glitter-j3b7sw?file=/src/App.js:0-1446检查工作代码框 - https://codesandbox.io/s/admiring-glitter-j3b7sw?file=/src/App.js:0-1446
import React, { useState } from "react";
import ProgressBar from "./ProgressBar";
import "./App.css";
var idCounter = 0;
export default function App() {
const [barsArray, setBarsArray] = useState([]);
const [input, setInput] = useState("");
function add() {
setBarsArray((prev) => [...prev, { id: idCounter++, restart: false }]);
}
function remove() {
setBarsArray((prev) =>
prev.filter((bar) => bar.id.toString() !== input.toString())
);
}
function reset() {
setBarsArray((prev) =>
prev.map((bar) => {
return bar.id.toString() === input.toString()
? { ...bar, restart: true }
: { ...bar };
})
);
}
return (
<div className="App">
<div className="buttons">
<button className="button-add" onClick={add}>
Add
</button>
<button className="button-delete" onClick={remove}>
Delete
</button>
<button className="button-delete" onClick={reset}>
Reset
</button>
<input
type="number"
value={input}
onInput={(e) => setInput(e.target.value)}
/>
</div>
<div className="bars-container">
{barsArray.map((bar) => (
<div className="bars-index" key={bar.id}>
<ProgressBar key={bar.id} restart={bar.restart} />
<p>{bar.key}</p>
</div>
))}
</div>
</div>
);
}
This simple fix worked for me, in the file of the child, call the conditional expression in a useEffect hook.这个简单的修复对我有用,在孩子的文件中,在 useEffect 挂钩中调用条件表达式。 Currently, it doesn't listen to the changes in props.restart and only runs on the initial render.
目前,它不监听 props.restart 的变化,只在初始渲染时运行。
check https://reactjs.org/docs/hooks-reference.html#useeffect检查https://reactjs.org/docs/hooks-reference.html#useeffect
useEffect(() => {
if (props.restart === true) {
setProgress(0);
}
}, [props.restart])
link to working codesandbox https://codesandbox.io/s/distracted-gauss-24d0pu链接到工作代码和框https://codesandbox.io/s/distracted-gauss-24d0pu
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.