reactjs - 调用 setState() 会执行函数值,而不是传递它
我有以下代码。按下按钮时,预期的行为是重新创建 AxiosInstance 并更新状态。但实际上,实例被重新创建后会在某处被执行。
function createApi(): AxiosInstance {
const api = axios.create();
// ...
return api;
}
function App() {
const [api, setApi] = React.useState<AxiosInstance>(() => createApi());
const resetApi = () => {
setApi(createApi());
};
console.log(api);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={resetApi}>Reset API</button>
</div>
);
}
在 Typescript 中没有错误,setApi 在我的 IDE 中具有以下签名:
React.Dispatch<React.SetStateAction<AxiosInstance>>
这将被评估为类似这样的结果:
(value: AxiosInstance) => void
这正是我在第一个代码片段中所做的,那么为什么它不起作用呢?
答案#1
好吧,所以显然 TypeScript 对我撒谎了,它并不像那样简单。AxiosInstance 有以下签名:
export interface AxiosInstance {
(config: AxiosRequestConfig): AxiosPromise;
(url: string, config?: AxiosRequestConfig): AxiosPromise;
...
}
所以 AxiosInstance 是一个 function,useState 在底层使用了 useReducer,在深入研究 ReactJS 代码库后,我发现 useReducer 中使用的 dispatch 函数只是简单地检查接收到的值是否是一个通用函数
function basicStateReducer<S>(state: S, action: BasicStateAction<S>): S {
return typeof action === 'function' ? action(state) : action;
}
因此,dispatch 错误地将 AxiosInstance(它本身是一个函数)当作回调函数,因为它是一个函数,并直接执行它。
解决方法很简单,使用回调来返回实例,而不是直接传入 setState
setApi(() => createApi())