javascript - React useEffect 清理函数意外调用

标签 javascript reactjs react-hooks

我正在创建一个自定义 Hook 来在表单提交时获取 api,我在 useEffect Hook 内进行 api 调用,并且我有一个 reducer 来处理 Hook 的状态。 其中一个状态首先将 trigger 设置为 false,它控制 useEffect 是否执行任何操作,重点是钩子(Hook)返回一个函数,该函数会翻转 trigger 值,该值仅触发 useEffect当你调用这个函数时。 问题是在 api 调用期间调用了 useEffect 的清理函数,即使该组件显然仍处于挂载状态。

清理函数似乎被触发,因为我根据之前的值设置了触发器的值,当我将触发器设置为固定值时,清理函数不会被触发打电话但我失去了我的功能

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};
}

用法:

function MyComponent () {
    const { datas, isLoading, isError, triggerFetch } = useFetchApi(query);
    return (
        <form onSubmit={event => {event.preventDefault(); triggerFetch()}}>
...

最佳答案

可以在 useEffect 回调内部使用局部变量。感谢@gaearon

https://codesandbox.io/s/k0lm13kwxo

  useEffect(() => {
    let ignore = false;

    async function fetchData() {
      const result = await axios('https://hn.algolia.com/api/v1/search?query=' + query);
      if (!ignore) setData(result.data);
    }

    fetchData();
    return () => { ignore = true; }
  }, [query]);

关于javascript - React useEffect 清理函数意外调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55376471/

相关文章:

javascript - 正则表达式只返回第一组

node.js - 如何将 React SSR 应用程序部署到 Heroku?

javascript - 如何解决 Stripe 元素 react 导致重定向内存泄漏

reactjs - 通过 id 重新选择 createSelector

reactjs - 无法更新 react Hook 中 setInterval 内的状态

Javascript - 如何根据定义的坐标修改复杂对象

javascript - 为什么我的 ajax.beginform 操作调用的部分 View 没有出现在页面上?

javascript - 在窗口调整大小时重新定位绝对定位元素的最佳实践

javascript - react : setState to a single component from multiple mapped instances of the same component

javascript - 严格模式禁止隐式创建全局属性 'inferred'