提问人:Epikdino 提问时间:10/13/2023 更新时间:10/13/2023 访问量:68
React 列表不会无缘无故更新(据我所知)
React list is not updated for no reason (as far as I know)
问:
我完成了 reactjs 教程并尝试制作我的第一页。 我制作了一个按钮来生成盒子,并在每个盒子中制作按钮来移动或删除它们。 我制作了一个移动部件不起作用的版本,我仍然不明白为什么。然后,我向 bard 询问了一个更简单的版本,然后对其进行了扩展以满足我的要求。你能帮我理解为什么第一个版本不起作用吗?基本上,图表(charts)的列表永远不会改变。图表的索引始终为 -1,但我的类型对我来说看起来不错...... 这是不起作用的代码:
import { useState } from 'react';
import './App.css';
function TopSelect({ gpios, addChart }){
const options = []
function handleSubmit(e){
e.preventDefault();
const data = new FormData(e.target);
const formJson = Object.fromEntries(data.entries());
addChart(formJson.gpios);
}
gpios.forEach(e => {
options.push(<option key={e} value={e}>GPIO{e}</option>);
})
return <form onSubmit={handleSubmit}>
<label>
GPIO
</label>
<select name="gpios">
{options}
</select>
<button type="submit">Add chart</button>
</form>;
}
function Chart({ gpio, pos, removeChart, moveChart}){
return <li key={pos}>
<h3>GPIO{gpio}</h3>
<button onClick={()=>moveChart(pos, false)}>Up</button>
<button onClick={()=>moveChart(pos, true)}>Down</button>
<button onClick={()=>removeChart(pos)}>Remove</button>
</li>;
}
function App() {
const [ gpios, setGpios ] = useState([]);
const [ charts, setCharts ] = useState([]);
const [ gpioInitialized, setGpioInitialized ] = useState(false);
function initGpio(){
let newGpio = [];
[1, 4, 7, 12].forEach(x => (
newGpio.push(x)
));
setGpios(newGpio);
}
function addChart(gpio){
let pos = 0;
if(charts.length > 0) pos = Math.max(...charts.map(c => c.id)) + 1;
const newChart = {id: pos ,
elem : <Chart gpio={gpio} pos={pos} removeChart={removeChart} moveChart={moveChart}/>};
setCharts([...charts, newChart ]);
}
function removeChart(pos){
setCharts((current) => current.filter((chart) => chart.id !== pos));
}
function moveChart(pos, down){
const index = charts.findIndex((chart) => chart.id === pos);
console.log(index);
if(!down){
if (index <= 0) return;
setCharts((charts) => {
const chartsCopy = [...charts];
const [chart] = chartsCopy.splice(index, 1);
chartsCopy.splice(index - 1, 0, chart);
});
}else{
if (index >= charts.length - 1) return;
setCharts((charts) => {
const chartsCopy = charts.slice();
const [chart] = chartsCopy.splice(index + 1, 1);
chartsCopy.splice(index, 0, chart);
});
}
}
if(!gpioInitialized){
initGpio();
setGpioInitialized(true);
}
return (
<div className="App">
<TopSelect gpios={gpios} addChart={addChart} />
<ul>
{
charts.map((chart) =>
chart.elem
)
}
</ul>
</div>
);
}
export default App;
这是工作版本:
import React, { useState } from "react";
function Menu({ gpios, addBox }){
const options = []
function handleSubmit(e){
e.preventDefault();
const data = new FormData(e.target);
const formJson = Object.fromEntries(data.entries());
addBox(formJson.gpios);
}
gpios.forEach(e => {
options.push(<option key={e} value={e}>GPIO{e}</option>);
})
return <form onSubmit={handleSubmit}>
<label>
GPIO
</label>
<select name="gpios">
{options}
</select>
<button type="submit">Add chart</button>
</form>;
}
function Box({ id, gpio, removeBox, moveBoxUp, moveBoxDown}){
const boxStyle = {
width: "100%",
height: "100px",
margin: "10px 0",
padding: "10px",
border: "1px solid black",
backgroundColor: "white",
};
let buttonUp = "";
let buttonDown = "";
if(moveBoxDown){
buttonDown = <button
onClick={() => moveBoxDown(id)}
>
Move Down
</button>;
}
if(moveBoxUp){
buttonUp = <button
onClick={() => moveBoxUp(id)}
>
Move Up
</button>;
}
return <li key={id}>
<div style={boxStyle}>
<h1>GPIO {gpio}</h1>
<button
onClick={() => removeBox(id)}
>
Remove
</button>
{buttonUp}
{buttonDown}
</div>
</li>;
}
function App(){
const [gpios, setGpios] = useState([]);
const [gpioInitialized, setGpioInitialized] = useState(false);
const [boxes, setBoxes] = useState([]);
function initGpios(){
if(gpioInitialized) return;
const available = [1,4,7,13];
setGpios(available);
setGpioInitialized(true);
}
function addBox(gpio){
const newBox = {
id: Date.now(),
gpio: gpio,
};
setBoxes([...boxes, newBox]);
};
function removeBox(id){
setBoxes(boxes.filter((box) => box.id !== id));
}
function moveBoxUp(id){
const index = boxes.findIndex((box) => box.id === id);
if (index > 0) {
setBoxes((boxes) => {
const boxesCopy = boxes.slice();
const [box] = boxesCopy.splice(index, 1);
boxesCopy.splice(index - 1, 0, box);
return boxesCopy;
});
}
}
function moveBoxDown(id){
const index = boxes.findIndex((box) => box.id === id);
if (index < boxes.length - 1) {
setBoxes((boxes) => {
const boxesCopy = boxes.slice();
const [box] = boxesCopy.splice(index + 1, 1);
boxesCopy.splice(index, 0, box);
return boxesCopy;
});
}
};
initGpios();
return (
<div>
<Menu gpios={gpios} addBox={addBox} />
<ul>
{boxes.map((box, index) => (
<Box id={box.id} gpio={box.gpio} removeBox={removeBox} moveBoxDown={(index===boxes.length-1)?null:moveBoxDown} moveBoxUp={(index===0)?null:moveBoxUp}/>
))}
</ul>
</div>
);
}
export default App;
有了新版本,盒子可以完美地移动。 谢谢! PS:如果您有任何提示或有些线条灼伤您的眼睛,请告诉我!
答:
我必须说,我已经浏览了您的代码,它看起来结构良好,对于初学者来说很不错。
我有几点可以考虑,以进一步改进你的代码:
开始使用 (https://www.freecodecamp.org/news/how-to-use-proptypes-in-react/) 或打字稿(这可能需要很多时间来学习),但我认为现在您可以继续。这有助于非常容易地捕获错误。
prop-types
prop-types
我可以看到你已经使用了 ,例如,尝试使用唯一标识符。
index
key
id
我认为应该避免内联样式,这样你的代码会更干净。
我相信您的代码可以进一步分解为多个新组件。
请尝试使用一致的变量名称。我可以看到你有和两者。
boxes
box
不过,作为学习者的良好开端!我鼓励你学习和成长更多。
<button onClick={()=>moveChart(pos, false)}>Up</button>
,这未按预期工作。正在发生的事情是一个函数以某种方式被注册(同时声明此 onclick),并且该函数使用的所有值 - 包括 ,也被注册。 因此,在添加 5 个图表后,您将其中一个图表向上移动,该函数将有一个长度为 1 的数组,而不是预期的 5,因此事情没有按预期工作。为什么会发生这种情况对我来说也是新事物,如果您发现它,请告诉我。moveChart
charts
moveChart
charts
您可以通过声明新状态来测试这一点。添加一次所有图表,然后尝试移动它们。理想情况下,您应该获得相同的输出,但您获得的值是声明 和 本身时的值。val
chart
onClick
const [val, setVal] = useState(-5);
递增函数中的状态,addChart
setVal((val) => val + 5);
setCharts([...charts, newChart]);
并在函数内部打印它 -moveChart
function moveChart(pos, down) {
console.log(pos, charts, val);
- 在声明 时已经定义了 for 上发生的事情,因此即使位置发生变化,函数也会调用将 old 作为其参数。
onClick
move
chart
move
pos
- 移动箱子时,您用来确定其位置的箱子不会改变。因此,它们现在被映射到错误的位置。
id
- 此外,请尝试向所有代码添加注释。
chart
我猜在任何地方都没有使用,const [chart] = chartsCopy.splice(index + 1, 1);
这些是我能找到的一些东西,也许还有更多。
评论