我打赌已经被回答了一百万次,但我还没有在谷歌上搜索过。我不知道如何简洁地表达这个问题。
作为学习项目,我正在尝试创建一个简单的 html 编辑工具,其中包括一个侧面板,您可以在其中编辑每个布局元素的不同属性,就像 Figma 中一样。问题是,在所述面板中,当我选择不同的元素时,输入值不会更新。
目标对象中的值按照计划很好地更改,但问题是当我从一个对象更改为另一个对象时,输入值仍然存在。
我在这里创建了一个隔离问题的演示https://codesandbox.io/p/sandbox/react-question-example-3qlyp5(也在下面)。在这里,我可以在两个对象中进行选择,并通过编辑输入来正确更改所述对象的“x”字段。但是,当我选择其他对象时,输入值不会更新以显示新对象字段的值。只有第一个选择才能正确更新字段值。
我很想删除输入并立即再次显示它,以重新实例化它,但这是次优的。因为这是一个学习项目,所以我最好问一下。
import "./styles.css";
import { useState } from "react";
const exampleThings = [
{
x: "12px",
i: 0,
a: "foo",
},
{
x: "5px",
i: 1,
a: "bar",
},
];
const positionParse = (pos) => {
const parsed = parseFloat(pos);
if (isNaN(parsed)) throw new Error("oops");
return parsed;
};
function PositionEditor({ setPositionDef, positionDef }) {
const [hasError, setHasError] = useState(false);
const [value, setValue] = useState(positionDef);
const changed = (e) => {
setValue(e.target.value);
try {
positionDef = positionParse(e.target.value);
setHasError(false);
setPositionDef(e.target.value);
} catch (e) {
setHasError(true);
}
};
return (
<input
type="text"
value={value}
onChange={changed}
style={{ borderColor: hasError ? "red" : "unset" }}
/>
);
}
function ThingSelector({ select, t }) {
return <button onClick={select}>Select thing {t} </button>;
}
export default function App() {
const [things, setThings] = useState([...exampleThings]);
const [selectedThing, setSelectedThing] = useState(undefined);
const selectThing = (i) => {
const thingIndex = things.findIndex((thing) => thing.i === i);
console.log("select thing", thingIndex);
setSelectedThing(things[thingIndex]);
};
const editThingPositionDef = (position) => {
const selectedThingId = things.findIndex((t) => t.i === selectedThing.i);
const newThings = [...things];
const newSelectedThing = {
...selectedThing,
x: position,
};
newThings[selectedThingId] = {
position,
...newSelectedThing,
};
setThings(newThings);
setSelectedThing(newSelectedThing);
};
return (
<div className="App">
{things.map((thing) => {
return (
<ThingSelector
select={(e) => selectThing(thing.i)}
t={thing.a}
key={thing.i}
/>
);
})}
{selectedThing === undefined ? (
<p>Select something</p>
) : (
<>
<p>
Editing: {selectedThing.a}. My x is {positionParse(selectedThing.x)}
</p>
<PositionEditor
setPositionDef={editThingPositionDef}
positionDef={selectedThing.x}
/>
</>
)}
</div>
);
}
好的!有趣的是,ChatGpt 给了我一个有用的答案!
我需要的是一个新的 useEffect 钩子 - 这就是为什么我需要一个真实的项目来了解钩子的使用。
这里是固定代码(唯一的变化是添加了 useEffect 钩子)
import "./styles.css";
import { useState, useEffect } from "react";
const exampleThings = [
{
x: "12px",
i: 0,
a: "foo",
},
{
x: "5px",
i: 1,
a: "bar",
},
];
const positionParse = (pos) => {
const parsed = parseFloat(pos);
if (isNaN(parsed)) throw new Error("oops");
return parsed;
};
function PositionEditor({ setPositionDef, positionDef }) {
const [hasError, setHasError] = useState(false);
const [value, setValue] = useState(positionDef);
useEffect(() => {
setValue(positionDef);
}, [positionDef]);
const changed = (e) => {
setValue(e.target.value);
try {
positionDef = positionParse(e.target.value);
setHasError(false);
setPositionDef(e.target.value);
} catch (e) {
setHasError(true);
}
};
return (
<input
type="text"
value={value}
onChange={changed}
style={{ borderColor: hasError ? "red" : "unset" }}
/>
);
}
function ThingSelector({ select, t }) {
return <button onClick={select}>Select thing {t} </button>;
}
export default function App() {
const [things, setThings] = useState([...exampleThings]);
const [selectedThing, setSelectedThing] = useState(undefined);
const selectThing = (i) => {
const thingIndex = things.findIndex((thing) => thing.i === i);
console.log("select thing", thingIndex);
setSelectedThing(things[thingIndex]);
};
const editThingPositionDef = (position) => {
const selectedThingId = things.findIndex((t) => t.i === selectedThing.i);
const newThings = [...things];
const newSelectedThing = {
...selectedThing,
x: position,
};
newThings[selectedThingId] = {
position,
...newSelectedThing,
};
setThings(newThings);
setSelectedThing(newSelectedThing);
};
return (
<div className="App">
{things.map((thing) => {
return (
<ThingSelector
select={(e) => selectThing(thing.i)}
t={thing.a}
key={thing.i}
/>
);
})}
{selectedThing === undefined ? (
<p>Select something</p>
) : (
<>
<p>
Editing: {selectedThing.a}. My x is {positionParse(selectedThing.x)}
</p>
<PositionEditor
setPositionDef={editThingPositionDef}
positionDef={selectedThing.x}
/>
</>
)}
</div>
);
}