React useAsync hook
处理异步调用。
- 创建一个自定义钩子,接受一个处理函数
fn
。 - 为自定义钩子的状态定义一个 reducer 函数和一个初始状态。
- 使用
useReducer()
钩子初始化state
变量和dispatch
函数。 - 定义一个异步的
run
函数,该函数将运行提供的回调函数fn
,并使用dispatch
根据需要更新state
。 - 返回一个包含
state
属性(value
、error
和loading
)和run
函数的对象。
const useAsync = fn => {
const initialState = { loading: false, error: null, value: null };
const stateReducer = (_, action) => {
switch (action.type) {
case 'start':
return { loading: true, error: null, value: null };
case 'finish':
return { loading: false, error: null, value: action.value };
case 'error':
return { loading: false, error: action.error, value: null };
}
};
const [state, dispatch] = React.useReducer(stateReducer, initialState);
const run = async (args = null) => {
try {
dispatch({ type: 'start' });
const value = await fn(args);
dispatch({ type: 'finish', value });
} catch (error) {
dispatch({ type: 'error', error });
}
};
return { ...state, run };
};
const RandomImage = props => {
const imgFetch = useAsync(url =>
fetch(url).then(response => response.json())
);
return (
<div>
<button
onClick={() => imgFetch.run('https://dog.ceo/api/breeds/image/random')}
disabled={imgFetch.isLoading}
>
加载图片
</button>
<br />
{imgFetch.loading && <div>加载中...</div>}
{imgFetch.error && <div>错误 {imgFetch.error}</div>}
{imgFetch.value && (
<img
src={imgFetch.value.message}
alt="avatar"
width={400}
height="auto"
/>
)}
</div>
);
};
ReactDOM.createRoot(document.getElementById('root')).render(
<RandomImage />
);