Gat*_*oyu 5 javascript reactjs react-hooks
我正在创建一个自定义钩子以在表单提交时获取 api,我在 useEffect 钩子内进行 api 调用,并且我有一个减速器来处理钩子的状态。其中一个状态首先trigger设置为 false 以控制 useEffect 是否执行任何操作,关键是钩子返回一个函数,trigger该函数只在您调用此函数时触发 useEffect 的值。问题是在 api 调用期间调用了 useEffect 的清理函数,即使该组件显然仍处于挂载状态。
清理功能似乎被触发,因为我trigger根据其先前的值设置trigger了 的值,当我设置为固定值时,不会调用清理功能,但我失去了功能
const fetchReducer = (state, action) => {
switch (action.type) {
case 'FETCH_TRIGGER':
return {
...state,
trigger: !state.trigger
}
case 'FETCH_INIT':
return {
...state,
isLoading: true,
isError: false
};
case 'FETCH_SUCCESS':
return {
...state,
isLoading: false,
isError: false,
datas: action.payload,
};
case 'FETCH_FAILURE':
return {
...state,
isLoading: false,
isError: true,
};
default:
throw new Error();
}
}
const useFetchApi = (query, initialData = []) => {
let isCancelled = false;
const [state, dispatch] = useReducer(fetchReducer, {
isLoading: false,
isError: false,
datas: initialData,
trigger: false
});
const triggerFetch = _ => dispatch({ type: 'FETCH_TRIGGER' });
const cancel = _ => { console.log("canceling");isCancelled = true };
useEffect(_ => {
if (!state.trigger)
return;
triggerFetch();
(async _ => {
dispatch({ type: 'FETCH_INIT' });
try {
const datas = await query();
if (!isCancelled) { //isCancelled is true at this point
dispatch({ type: 'FETCH_SUCCESS', payload: datas })
}
} catch (err) {
if (!isCancelled) {
dispatch({ type: 'FETCH_FAILURE', payload: err })
}
}
})();
return cancel;
}, [state.trigger]);
return { ...state, triggerFetch};
}
Run Code Online (Sandbox Code Playgroud)
用法:
function MyComponent () {
const { datas, isLoading, isError, triggerFetch } = useFetchApi(query);
return (
<form onSubmit={event => {event.preventDefault(); triggerFetch()}}>
...
Run Code Online (Sandbox Code Playgroud)
汤姆·芬尼(Tom Finney)的评论中的解决方案:
You could add another use effect that didn't do anything except for return that cancel function and have it with an empty array dependency that would mimic componentWillUnmount like useEffect(() => cancel, [])
const useFetchApi = (query, initialData = []) => {
let isCancelled = false;
const [state, dispatch] = useReducer(fetchReducer, {
isLoading: false,
isError: false,
datas: initialData,
trigger: false
});
const triggerFetch = _ => dispatch({ type: 'FETCH_TRIGGER' });
const cancel = _ => { console.log("canceling");isCancelled = true };
useEffect(_ => {
if (!state.trigger)
return;
triggerFetch();
(async _ => {
dispatch({ type: 'FETCH_INIT' });
try {
const datas = await query();
if (!isCancelled) {
dispatch({ type: 'FETCH_SUCCESS', payload: datas })
}
} catch (err) {
if (!isCancelled) {
dispatch({ type: 'FETCH_FAILURE', payload: err })
}
}
})();
}, [state.trigger]);
useEffect(_=> cancel, []) //remove return cancel from useEffect and replace by this
return { ...state, triggerFetch};
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6781 次 |
| 最近记录: |