React Hooks 常见错误
前言
本片文章主要是在写react hooks的时候,遇到的常见错误的写法,和错误。也是一个对只是的巩固和总结。
错误一
上代码:正确写法
function TestReactHooksError() {
const [test, setTest] = useState('test');
useEffect(() => {
if(test) {
console.log(test)
}
}, [test]);
return (
<div>
<button onClick={()=>setTest(test + 1)}>{test}click</button>
</div>
);
}
export default TestReactHooksError
解析:
功能,点击按钮,按钮文案改动,并且控制台打印文案结果。
稍作改动:
function TestReactHooksError() {
const [test, setTest] = useState('test');
if (test) {
useEffect(() => {
console.log(test)
}, [test]);
}
return (
<div>
<button onClick={() => setTest(test + 1)}>{test}click</button>
</div>
);
}
export default TestReactHooksError
可以看到报错了:
搜狗翻译:
React钩子“useEffect”被有条件地调用。React挂钩必须在每个组件渲染中以完全相同的顺序调用
正常翻译:
就是钩子函数必须按顺序执行,因为底层是按顺序执行的,所以如果加入判断的话,可能有不可预知的错误。
错误二
上代码:正确写法
function TestReactHooksError() {
const [test, setTest] = useState([1, 2, 3, 4, 5]);
useEffect(() => {
consoleLog()
}, []);
const consoleLog = (value) => {
for (let i = 0, len = test.length; i < len; i++) {
console.log(test[i])
}
}
return (
<div>
{
test.map((item) => {
return <span key={item}>{item}</span>
})
}
</div>
);
}
export default TestReactHooksError
解析:
功能,渲染列表,并且控制台打印结果。
稍作改动:
function TestReactHooksError() {
const [test, setTest] = useState([1,2,3,4,5]);
for (let i=0, len = test.length; i < len; i++) {
useEffect(() => {
console.log(test[i])
}, [test[i]]);
}
return (
<div>
{
test.map((item)=>{
return <span key={item}>{item}</span>
})
}
</div>
);
}
export default TestReactHooksError
报错:
可以看到结果都正常打印了,但是报错了。
搜狗翻译:
React挂钩“useEffect”可以执行多次。可能是因为它是在循环中调用的。React挂钩必须在每个组件渲染中以完全相同的顺序调用
正常翻译:
不能在循环中使用hooks,因为还是可能会导致执行顺序错误,导致结果错误。
错误三
上代码: 正确写法
function TestReactHooksError() {
const [testState, setTestState] = useState('testState')
const clickState = () => {
console.log(testState)
}
return (
<div>
<button onClick={()=>clickState()}>click</button>
</div>
);
}
export default TestReactHooksError
解析:
功能,点击按钮控制台打印结果。
稍作改动:
function TestReactHooksError() {
const clickState = () => {
const [testState, setTestState] = useState('testState')
console.log(testState)
}
return (
<div>
<button onClick={()=>clickState()}>click</button>
</div>
);
}
export default TestReactHooksError
报错:
搜狗翻译:
React挂钩“useState”在函数“clickState”中调用,该函数既不是React函数组件,也不是自定义React挂钩函数。React组件名称必须以大写字母开头。React挂钩名称必须以单词“use”开头
正常翻译:
这个翻译的很明白,就是不能在普通函数中使用,因为react不会理解它是一个组件或者是自定义hooks。
错误四
上代码: 错误写法
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
testState: 'testState',
};
}
useEffect(() => {
console.log(this.state.testState)
}, [this.state.testState]);
render() {
return (
<div>
<p>You clicked {this.state.testState} times</p>
<button onClick={() => this.setState({ testState: this.state.testState + 1 })}>
Click
</button>
</div>
);
}
}
报错:
报错语法格式错误。所以不能混合使用
错误五
正确的写法:
function TestReactHooksError() {
const [testState, setTestState] = useState('testState')
function clickState() {
console.log(testState)
}
return (
<div>
<button onClick={() => setTestState(testState + 1)}>{testState}</button>
<button onClick={() => clickState()}>click</button>
</div>
);
}
export default TestReactHooksError
稍作修改:
function TestReactHooksError() {
const [testState, setTestState] = useState('testState')
function clickState() {
console.log(testState)
}
return (
<div>
<button onClick={() => setTestState(testState + 1)}>{testState}</button>
<button onClick={clickState}>click</button>
</div>
);
}
export default TestReactHooksError
在 JSX 的事件处理程序中调用函数时,应该传递函数本身而不是函数的返回值。改为 onClick={() => handleClick()} 或者将 handleClick 函数定义在组件外部并将其作为 prop 传递给组件。由于当前的写法每次渲染都会创建一个新的函数和事件处理程序,因此会导致浪费和性能问题。
注意:
当然在最新的版本中不会有这个问题因为,React 已经对函数事件处理程序进行了自动绑定,所以在最新版本中不会出现这个问题。这是因为最新版本的 React 使用了异步渲染机制,将多次渲染时创建的函数缓存起来进行重用,从而避免了性能问题。
错误六
使用useEffect时没有传入依赖项,这可能会导致无限制地执行useEffect,当然如果你就是为了重复执行可以跳过这个。
正确写法:
function TestReactHooksError() {
const [test, setTest] = useState('test');
useEffect(() => {
console.log(test)
}, [test]);
return (
<div>
<button onClick={()=>setTest(test + 1)}>{test}click</button>
</div>
);
}
export default TestReactHooksError
稍作修改:
function TestReactHooksError() {
const [test, setTest] = useState('test');
useEffect(() => {
console.log(test)
});
return (
<div>
<button onClick={()=>setTest(test + 1)}>{test}click</button>
</div>
);
}
export default TestReactHooksError
修改之后,如果之后再加入其他按钮渲染数据,当其他数据变化时,还是会执行useEffect,所以需要正确的添加,依赖项。
错误七
定时器
上代码:正确的写法
分别使用setTimeout和setInterval
function TestReactHooksError() {
const [timer, setTimer] = useState(0);
const [timerS, setTimerS] = useState(0);
useEffect(() => {
setTimeout(() => {
setTimer(timer + 1)
}, 1000)
}, [timer]);
useEffect(() => {
setInterval(() => {
setTimerS(timerS => timerS + 1)
}, 1000)
}, []);
return (
<div>
{timer}-{timerS}
</div>
);
}
export default TestReactHooksError
但是这样写有一个问题,如果仔细看页面计时显示会发现两个时间有偏差。setTimeout会慢一些,但是这也不难分析,因为setTimeout 和 setInterval 的执行方式是不同的。setTimeout 在每次计时器更新时都会重新创建一个新的计时器,而 setInterval 只会在组件挂载时创建一个计时器。因此,setInterval 的计时器会一直运行,而 setTimeout 的计时器则会受到上一个计时器执行时间的影响,可能会出现延迟。另外,由于 setTimeout 是在依赖数组中的 timer 更新时执行的,当 timer 发生变化时,会重新创建一个新的计时器,这可能会导致计时器的执行时间出现偏差。
说简单点就是,setInterval 每次只是在设定的时间后马上执行,而setTimeout需要依赖数据变化并且每次都重新创建,所以会慢一些
稍作修改
错误的写法:
useEffect(() => {
setInterval(() => {
setTimerS(timerS + 1)
console.log(timerS)
}, 1000)
}, [timerS]);
可以看到页面显示抽搐的时间
总结
先这么多文章还会更新。。。
如有问题欢迎指出,感谢