React 获取空状态
2022-10-23
77
我正在尝试创建一个高级正则表达式搜索应用程序,以便我搜索某些内容并将其替换到其他行中,但我正在努力完成一项更简单的任务:无法删除规则,因为
rules
状态似乎为空:
export default function App() {
const [displayNewRule, setDisplayNewRule] = useState(false);
const [replaceType, setReplaceType] = useState("line");
const [rules, setRules] = useState([]);
function handleClick() {
setDisplayNewRule(true);
}
function handleSubmit(e) {
e.preventDefault();
const rule = {
name: e.target.name.value,
sourceSearchPattern: e.target.sourceSearchPattern.value,
replaceType,
value: e.target.value.value
};
if (replaceType === "occurrence") {
rule.targetSearchPattern = e.target.targetSearchPattern.value;
rule.location = e.location.value;
}
let $rules = rules;
$rules.push(rule);
setRules($rules);
e.target.reset();
handleReset();
}
function handleReset() {
setDisplayNewRule(false);
}
function deleteRule(i) {
let $rules = rules;
$rules.splice(i, 1);
setRules($rules);
// this gets an empty rules
}
return (
<div className="App">
<form
onSubmit={handleSubmit}
onReset={handleReset}
style={{ display: displayNewRule || "none" }}
>
<h3>Create new rule</h3>
<div className="input-group">
<label htmlFor="name">Name:</label>
<input type="text" id="name" name="name" required />
</div>
<div className="input-group">
<label htmlFor="sourceSearchPattern">Source search pattern:</label>
<input
type="text"
id="sourceSearchPattern"
name="sourceSearchPattern"
required
/>
</div>
<div className="input-group">
<label htmlFor="replaceType">Replace type:</label>
<select
id="replaceType"
name="replaceType"
onChange={(e) => {
setReplaceType(e.target.value);
}}
required
>
<option value="">Select item</option>
<option value="line">Replace line</option>
<option value="occurrence">Replace occurrence</option>
</select>
</div>
{replaceType === "occurrence" && (
<div className="input-group">
<label htmlFor="targetSearchPattern">Target search pattern:</label>
<input
type="text"
id="targetSearchPattern"
name="targetSearchPattern"
required
/>
</div>
)}
<div className="input-group">
<label htmlFor="value">Value:</label>
<input type="text" id="value" name="value" required />
</div>
{replaceType === "occurrence" && (
<div className="input-group">
Occurrence location:
<div className="option-group">
<input
type="radio"
id="next-occurrence"
name="location"
value="next"
required
/>
<label htmlFor="next-occurrence">Next occurrence</label>
</div>
<div className="option-group">
<input
type="radio"
id="previous-occurrence"
name="location"
value="previous"
/>
<label htmlFor="previous-occurrence">Previous occurrence</label>
</div>
</div>
)}
<button type="submit">Submit</button>
<button type="reset">Cancel</button>
</form>
<button onClick={handleClick}>Add rule</button>
<div className="rules">
<h3>Rules</h3>
{rules.map((rule, i) => ( // These rules are being displayed.
<div className="rule" key={i + 1}>
<h5>
{rule.name}
<button
onClick={() => {
deleteRule(i);
}}
>
Delete rule
</button>
</h5>
<p>Replace type: {rule.replaceType}</p>
<p>Source search pattern: {rule.sourceSearchPattern}</p>
</div>
))}
</div>
</div>
);
}
有什么线索吗?
2个回答
而不是
let $rules = rules;
$rules.push(rule);
setRules($rules);
尝试
setRules(oldRules => [...oldRules, rule]);
您正在当前代码中改变状态,这是一个巨大的反模式。我不确定它是否导致了您看到的问题,但更改为此模式将使调试和消除变量变得更容易。还要更改您的
deleteRule
函数,使其同样不会改变状态(使用 [...] 规则复制状态并在设置新规则之前对其进行操作)。
Nathan
2022-10-23
tl;dr - 您的组件 根本不 重新渲染。
更多说明:
$rules
保留
state
对象
rules
的引用(它是同一个实例)。调用
setRules
时,
浅比较
会进入并阻止您更新组件(由于直接
突变
,新值与当前值
完全相同
)。
有人会问,为什么 浅比较 会阻止组件重新渲染,因为它仅适用于 基元 (数组 不是 )。问题是 浅比较 仍然适用于持有 相同引用 的对象。
const array = [];
array === array // true;
带有分步描述的代码:
function handleSubmit() {
let $rules = rules; // $rules holds the reference and is the same instance as rules
$rules.push(rule); // directly updated state (mutated)
// value of $rules and rules is again exactly the same!
setRules($rules); // the component is not even updated because of the
// shallow comparison - $rules and rules is the same instance
// with exactly the same value
}
解决方案是避免直接变异。
setRules((oldRules) => [...oldRules, rule]);
如@Nathan 上面发布的那样。
kind user
2022-10-23