import { useState } from "react";
type Rule = {
value: string;
valid: boolean;
};
type RuleComponentProps = {
rule: Rule;
setValue: (value: string) => void;
setValid: (valid: boolean) => void;
};
function RuleComponent({ rule, setValue, setValid }: RuleComponentProps) {
function validator(value: string) {
rule.valid = !!value;
// Why below line doesn't work?
// setValid(!!value);
}
function handleChange(e: any) {
const value = e.target.value;
validator(value);
setValue(value);
// rule.value = value;
}
return <input onChange={handleChange} value={rule.value} />;
}
export default function App() {
const [ruleList, setRuleList] = useState<Rule[]>([]);
function addRule() {
setRuleList((prev) => [...prev, { value: "", valid: false }]);
}
function getSetValueMeth(index: number) {
return (value: string) => {
const newRuleList = ruleList.map((rule, i) => {
if (index === i) {
return { ...rule, value };
}
return rule;
});
setRuleList(newRuleList);
};
}
function getSetValidMeth(index: number) {
return (valid: boolean) => {
const newRuleList = ruleList.map((rule, i) => {
if (index === i) {
return { ...rule, valid };
}
return rule;
});
setRuleList(newRuleList);
};
}
return (
<div className="App">
<div>
<button onClick={() => addRule()}>Add rule</button>
</div>
{ruleList.map((rule, index) => (
<p key={index}>
Rule{index}:{" "}
<RuleComponent
rule={rule}
setValue={getSetValueMeth(index)}
setValid={getSetValidMeth(index)}
/>
</p>
))}
<p>{JSON.stringify(ruleList)}</p>
<button onClick={() => console.log(ruleList)}>Show Rule List</button>
</div>
);
}
我正在尝试编辑上面代码中规则列表中的有效值,它在使用
rule.valid = !!value;
时工作,但是当我更改为 setValid(!!value);
方法时,有效值没有改变,即使调用了 setRuleList
钩子并使用正确更新了newRuleList
我为此创建了一个CodeSandbox:https://codesandbox.io/p/sandbox/react-demo-dfs236?file=%2Fsrc%2FApp.tsx%3A17%2C29,可以直接调试。
我知道在 React 中直接编辑值是不合适的,但为什么钩子不起作用?完成我的功能的正确方法是什么?
setValid
(validator
) 中的
getSetValidMeth
调用进行的排队状态更新被 setValue
中的 handleChange
调用进行的排队状态更新消除,因为每个都对未更新的状态有一个闭包ruleList
调用 handleChange
时的状态值。
使用功能状态更新,以便每个排队更新正确更新任何先前的状态值,而不是回调范围中关闭的任何值。
const getSetValueMeth = (index: number) => (value: string) =>
setRuleList((ruleList) =>
ruleList.map((rule, i) => (index === i ? { ...rule, value } : rule))
);
const getSetValidMeth = (index: number) => (valid: boolean) =>
setRuleList((ruleList) =>
ruleList.map((rule, i) => (index === i ? { ...rule, valid } : rule))
);
完整代码:
function RuleComponent({ rule, setValue, setValid }: RuleComponentProps) {
function validator(value: string) {
setValid(!!value);
}
function handleChange(e: any) {
const value = e.target.value;
validator(value);
setValue(value);
}
return <input onChange={handleChange} value={rule.value} />;
}
export default function App() {
const [ruleList, setRuleList] = useState<Rule[]>([]);
function addRule() {
setRuleList((prev) => [...prev, { value: "", valid: false }]);
}
const getSetValueMeth = (index: number) => (value: string) =>
setRuleList((ruleList) =>
ruleList.map((rule, i) => (index === i ? { ...rule, value } : rule))
);
const getSetValidMeth = (index: number) => (valid: boolean) =>
setRuleList((ruleList) =>
ruleList.map((rule, i) => (index === i ? { ...rule, valid } : rule))
);
return (
<div className="App">
<div>
<button onClick={() => addRule()}>Add rule</button>
</div>
{ruleList.map((rule, index) => (
<p key={index}>
Rule{index}:{" "}
<RuleComponent
rule={rule}
setValue={getSetValueMeth(index)}
setValid={getSetValidMeth(index)}
/>
</p>
))}
<p>{JSON.stringify(ruleList)}</p>
<button onClick={() => console.log(ruleList)}>Show Rule List</button>
</div>
);
}