无限循环 React 钩子
Infinite loop React hooks
我不明白为什么我会进入无限循环
useClick 我看到我使用 setVal 更改了 useEffect 中的状态值,但是 useEffect 应该只在 onClick 上工作,因为在第二个参数中指定。我认为这是因为我传递的参数 onClick 被记忆但没有调用回调(我使用 console.log('go set')[=11= 检查过]
function useClick(onClick, setVal, val) {
React.useEffect(() => {
console.log('Click');
setVal(val + 1);
}, [onClick]);
}
const Home = () => {
const [val, setVal] = React.useState(0);
const incrementOnClick = React.useCallback(() => {
console.log('go set');
setVal(val + 1);
} , [setVal, val]);
useClick(incrementOnClick, setVal, val);
return <div>
<div>{val}</div>
<button onClick={incrementOnClick}>Click me</button>
</div>
}
val
和 setVal
将在每次渲染时发生变化,这反过来又会导致 incrementOnClick
成为新的函数引用,并且您的 useClick
效果将始终是调用。
您可以将一个函数作为 setVal
的第一个参数。此函数获取当前 val
作为参数,并获取 returns 新值。这样 incrementOnClick
将始终是相同的函数。
const { useEffect, useState, useCallback } = React;
function useClick(onClick, setVal, val) {
useEffect(() => {
console.log("Click");
setVal(val + 1);
}, [onClick]);
}
const Home = () => {
const [val, setVal] = useState(0);
const incrementOnClick = useCallback(() => {
console.log("go set");
setVal(val => val + 1);
}, []);
useClick(incrementOnClick, setVal, val);
return (
<div>
<div>{val}</div>
<button onClick={incrementOnClick}>Click me</button>
</div>
);
};
ReactDOM.render(<Home />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
上面的代码展示了如何摆脱无限循环并且可能对实验有价值,但其中大部分都不是必需的。您可以像这样编写相同的功能:
const { useState } = React;
const Home = () => {
const [val, setVal] = useState(1);
return (
<div>
<div>{val}</div>
<button onClick={() => setVal(val + 1)}>Click me</button>
</div>
);
};
ReactDOM.render(<Home />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
看看你想做什么,我相信你错过了 Hooks & React 最有用的功能之一,那就是组合。
这是您所做工作的示例,但只是创建另一个名为 <IncrementButton/>
的组件,对我来说,这只会让代码更容易理解/调试。自定义挂钩很棒,但我认为这样做是错误的工具..
const { useEffect, useState } = React;
const IncrementButton = props => {
const {val, setVal, children} = props;
return <button
onClick={() => setVal(val + 1)}
>{children}</button>;
}
const Home = () => {
const [val, setVal] = useState(0);
return (
<div>
<div>{val}</div>
<IncrementButton val={val} setVal={setVal}>
Click me
</IncrementButton>
</div>
);
};
ReactDOM.render(<Home />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
我不明白为什么我会进入无限循环 useClick 我看到我使用 setVal 更改了 useEffect 中的状态值,但是 useEffect 应该只在 onClick 上工作,因为在第二个参数中指定。我认为这是因为我传递的参数 onClick 被记忆但没有调用回调(我使用 console.log('go set')[=11= 检查过]
function useClick(onClick, setVal, val) {
React.useEffect(() => {
console.log('Click');
setVal(val + 1);
}, [onClick]);
}
const Home = () => {
const [val, setVal] = React.useState(0);
const incrementOnClick = React.useCallback(() => {
console.log('go set');
setVal(val + 1);
} , [setVal, val]);
useClick(incrementOnClick, setVal, val);
return <div>
<div>{val}</div>
<button onClick={incrementOnClick}>Click me</button>
</div>
}
val
和 setVal
将在每次渲染时发生变化,这反过来又会导致 incrementOnClick
成为新的函数引用,并且您的 useClick
效果将始终是调用。
您可以将一个函数作为 setVal
的第一个参数。此函数获取当前 val
作为参数,并获取 returns 新值。这样 incrementOnClick
将始终是相同的函数。
const { useEffect, useState, useCallback } = React;
function useClick(onClick, setVal, val) {
useEffect(() => {
console.log("Click");
setVal(val + 1);
}, [onClick]);
}
const Home = () => {
const [val, setVal] = useState(0);
const incrementOnClick = useCallback(() => {
console.log("go set");
setVal(val => val + 1);
}, []);
useClick(incrementOnClick, setVal, val);
return (
<div>
<div>{val}</div>
<button onClick={incrementOnClick}>Click me</button>
</div>
);
};
ReactDOM.render(<Home />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
上面的代码展示了如何摆脱无限循环并且可能对实验有价值,但其中大部分都不是必需的。您可以像这样编写相同的功能:
const { useState } = React;
const Home = () => {
const [val, setVal] = useState(1);
return (
<div>
<div>{val}</div>
<button onClick={() => setVal(val + 1)}>Click me</button>
</div>
);
};
ReactDOM.render(<Home />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
看看你想做什么,我相信你错过了 Hooks & React 最有用的功能之一,那就是组合。
这是您所做工作的示例,但只是创建另一个名为 <IncrementButton/>
的组件,对我来说,这只会让代码更容易理解/调试。自定义挂钩很棒,但我认为这样做是错误的工具..
const { useEffect, useState } = React;
const IncrementButton = props => {
const {val, setVal, children} = props;
return <button
onClick={() => setVal(val + 1)}
>{children}</button>;
}
const Home = () => {
const [val, setVal] = useState(0);
return (
<div>
<div>{val}</div>
<IncrementButton val={val} setVal={setVal}>
Click me
</IncrementButton>
</div>
);
};
ReactDOM.render(<Home />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>