Uji*_*T34 7 javascript reactjs eslint react-hooks
该钩的规则要求,同样的挂钩,并在同一顺序呼吁每一个渲染。并且有一个关于如果您违反此规则会出问题的解释。例如此代码:
function App() {
console.log('render');
const [flag, setFlag] = useState(true);
const [first] = useState('first');
console.log('first is', first);
if (flag) {
const [second] = useState('second');
console.log('second is', second);
}
const [third] = useState('third');
console.log('third is', third);
useEffect(() => setFlag(false), []);
return null;
}
Run Code Online (Sandbox Code Playgroud)
输出到控制台
render
first is first
second is second
third is third
render
first is first
third is second
Run Code Online (Sandbox Code Playgroud)
并导致警告或错误。
但是,在元素生命周期中不会改变的条件又如何呢?
const DEBUG = true;
function TestConst() {
if (DEBUG) {
useEffect(() => console.log('rendered'));
}
return <span>test</span>;
}
Run Code Online (Sandbox Code Playgroud)
这段代码并没有真正违反规则,似乎可以正常工作。但是它仍然会触发eslint警告。
而且,似乎有可能基于道具编写类似的代码:
function TestState({id, debug}) {
const [isDebug] = useState(debug);
if (isDebug) {
useEffect(() => console.log('rendered', id));
}
return <span>{id}</span>;
}
function App() {
const [counter, setCounter] = useState(0);
useEffect(() => setCounter(1), []);
return (
<div>
<TestState id="1" debug={false}/>
<TestState id="2" debug={true}/>
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
此代码按预期工作。
因此,当我确定它不会改变时,在条件内调用钩子是否安全?是否可以修改eslint规则以识别这种情况?
问题更多是关于实际需求,而不是实现类似行为的方式。据我了解,
确保每次渲染组件时都以相同的顺序调用Hook。这就是让React在多个useState和useEffect调用之间正确保留Hook的状态的原因
该规则有一个例外的地方:“不要在循环,条件或嵌套函数内调用Hooks”。
尽管您可以像上面提到的那样有条件地编写钩子,并且它可能在当前工作,但将来可能会导致预期的行为。例如,在当前情况下,您无需修改isDebug状态。
演示版
const {useState, useEffect} = React;
function TestState({id, debug}) {
const [isDebug, setDebug] = useState(debug);
if (isDebug) {
useEffect(() => console.log('rendered', id));
}
const toggleButton = () => {
setDebug(prev => !prev);
}
return (
<div>
<span>{id}</span>
<button type="button" onClick={toggleButton}>Toggle debug</button>
</div>
);
}
function App() {
const [counter, setCounter] = useState(0);
useEffect(() => setCounter(1), []);
return (
<div>
<TestState id="1" debug={false}/>
<TestState id="2" debug={true}/>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('app'));Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="app"/>Run Code Online (Sandbox Code Playgroud)
根据经验,您不应该违反规则,因为这可能是将来出现问题的原因。您可以通过以下方式处理上述情况,而不会违反规则
const {useState, useEffect} = React;
function TestState({id, debug}) {
const [isDebug, setDebug] = useState(debug);
useEffect(() => {
if(isDebug) {
console.log('rendered', id)
}
}, [isDebug]);
const toggleButton = () => {
setDebug(prev => !prev);
}
return (
<div>
<span>{id}</span>
<button type="button" onClick={toggleButton}>Toggle debug</button>
</div>
);
}
function App() {
const [counter, setCounter] = useState(0);
useEffect(() => setCounter(1), []);
return (
<div>
<TestState id="1" debug={false}/>
<TestState id="2" debug={true}/>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('app'));Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="app"/>Run Code Online (Sandbox Code Playgroud)
对于您的用例,我没有看到问题,我不知道将来会如何打破这种情况,而且您认为它按预期工作是正确的。
但是,我认为警告实际上是合法的,应该始终存在,因为这可能是您代码中的潜在错误(不是在这个特定的错误中)
所以我会在你的情况下做的是禁用react-hooks/rules-of-hooks该行的规则。
参考:https : //reactjs.org/docs/hooks-rules.html
| 归档时间: |
|
| 查看次数: |
1521 次 |
| 最近记录: |