Javascript 如何在usePromise钩子中将参数传递给promise
我创建了一个Javascript 如何在usePromise钩子中将参数传递给promise,javascript,reactjs,promise,react-hooks,react-16,Javascript,Reactjs,Promise,React Hooks,React 16,我创建了一个usePromiseReact钩子,它应该能够解析每一种javascript承诺,并返回每一个结果和状态:数据、解析状态和错误。 我可以让它在没有任何参数的情况下传递函数,但是当我尝试将其更改为允许使用参数时,我得到了一个无限循环 const usePromise = (promise: any): [any, boolean, any] => { const [data, setData] = useState<object | null>(null);
usePromise
React钩子,它应该能够解析每一种javascript承诺,并返回每一个结果和状态:数据、解析状态和错误。
我可以让它在没有任何参数的情况下传递函数,但是当我尝试将其更改为允许使用参数时,我得到了一个无限循环
const usePromise = (promise: any): [any, boolean, any] => {
const [data, setData] = useState<object | null>(null);
const [error, setError] = useState<object | null>(null);
const [fetching, setFetchingState] = useState<boolean>(true);
useEffect(() => {
setFetchingState(true);
promise
.then((data: object) => {
setData(data);
})
.catch((error: object) => {
setError(error);
})
.finally(() => {
setFetchingState(false);
});
}, [promise]);
return [data, fetching, error];
};
const apiCall = (param?: string): Promise<any> => {
return new Promise(resolve => {
setTimeout(() => {
resolve({ response: `Response generated with your param ${param}.` });
}, 500);
});
};
const App = (): React.Element => {
// How can I pass an argument to apiCall?
const [response, fetching, error] = usePromise(apiCall(5));
console.log("render"); // This logs infinitely
return <div>{JSON.stringify({ response, fetching, error })}</div>;
};
constUsePromise=(promise:any):[any,boolean,any]=>{
const[data,setData]=useState(null);
const[error,setError]=useState(null);
常量[fetching,setFetchingState]=useState(true);
useffect(()=>{
setFetchingState(true);
承诺
.然后((数据:对象)=>{
setData(数据);
})
.catch((错误:对象)=>{
设置错误(错误);
})
.最后(()=>{
setFetchingState(假);
});
},[承诺];
返回[数据,获取,错误];
};
常量apiCall=(参数?:字符串):承诺
和错误在(选项卡卡住,被警告):
注意:我希望在不使用来自NPM的usePromise单函数库的情况下找到解决方案,或者类似的自定义挂钩可能会执行多次。您应该这样设计,即您只想做一次的所有事情(例如API调用)都在useffect
hook中。这可以通过接受回调来实现,然后在钩子中调用回调
另外,稍微安全一些:
const usePromise = <T>(task: () => Promise<T>) => {
const [state, setState] = useState<[T?, boolean, Error?]>([null, true, null]);
useEffect(() => {
task()
.then(result => setState([result, false, null])
.catch(error => setState([null, false, error]);
}, []); // << omit the condition here, functions don't equal each other²
return state;
};
// Then used as
usePromise(() => apiCall(5));
您的代码是否处理所有类型的响应?如果没有,则删除[promise]作为依赖项,并在UsePromise中调用like()=>apiCall(5)原因是useEffect
具有依赖项promise
,该函数包含setTimeOut
/promise
,并且每次组件呈现时,一个新的setTimeout被从API部分推送到callbackQueue,从而无限异步并导致重新渲染Hey@Jonas非常感谢您的回答。我发现,如果安装了组件并且apiCall
的参数发生变化,则useconomise
结果不会更新。我认为它应该接收函数的参数作为钩子比较器(useffect的第二个参数)。你怎么认为?这很难。当前正在进行的API调用会发生什么情况?确保取消操作正确,并小心使用参数。对象在react中通过引用进行比较。是的,这是一个很好的观点!如果您有比我更好的usePromise
或通用解决方案,请分享。多谢各位@rashomon是的,我有一个我经常使用的,不确定它是否完全适合你的用例。
export function useAPI<Q, R>(api: (query: Q) => Promise<R | never>) {
const [state, setState] = useState<{ loading?: true, pending?: true, error?: string, errorCode?: number, result?: R }>({ pending: true });
async function run(query: Q) {
if(state.loading) return;
setState({ loading: true });
try {
const result = await api(query);
setState({ result });
} catch(error) {
if(error instanceof HTTPError) {
console.error(`API Error: ${error.path}`, error);
setState({ error: error.message, errorCode: error.code });
} else {
setState({ error: error.message, errorCode: NaN });
}
}
}
function reset() {
setState({ pending: true });
}
return [state, run, reset] as const;
}