如何使用useReducer和useEffect从API获取数据,同时仍然允许重新查询

时间:2020-01-26 05:38:15

标签: reactjs react-hooks

this出色的指南之后,我有一个自定义钩子,如果API URL更改,它将自动重新获取。我想要这种行为,但我也希望能够根据需要从组件中重新查询。

const useDataApi = (initialUrl, initialData) => {
    const [url, setUrl] = useState(initialUrl);
    const [state, dispatch] = useReducer(dataFetchReducer, {
        isLoading: false,
        isError: false,
        data: initialData,
    });

    useEffect(() => {
        const fetchData = async () => {
            dispatch({ type: 'FETCH_INIT' });
            try {
                const result = await axios(url);
                dispatch({ type: 'FETCH_SUCCESS', payload: result.data });
            } catch (error) {
                dispatch({ type: 'FETCH_FAILURE' });
            }
        };
        fetchData();
    }, [url]);

    return [state, setUrl];
};

如果我从组件中调用setUrl,并两次将相同的URL传递给它(例如由于刷新按钮onClicked),它将不会重新访问,因为useEffect未检测到{ {1}}依赖性。

启用我期望的行为的最佳方法是什么?

1 个答案:

答案 0 :(得分:0)

根据您的要求,您可以在每次调用attempt方法时使用另一种状态updateUrl进行更改。代替直接公开setUrl,公开updateUrl可以解决问题。

const useDataApi = (initialUrl, initialData) => {
    const [url, setUrl] = useState(initialUrl);
    const [attempt, setAttempt] = useState(false);
    const [state, dispatch] = useReducer(dataFetchReducer, {
        isLoading: false,
        isError: false,
        data: initialData,
    });

    useEffect(() => {
        const fetchData = async () => {
            dispatch({ type: 'FETCH_INIT' });
            try {
                const result = await axios(url);
                dispatch({ type: 'FETCH_SUCCESS', payload: result.data });
            } catch (error) {
                dispatch({ type: 'FETCH_FAILURE' });
            }
        };
        fetchData();
    }, [url, attempt]);

    const updateUrl = useCallback((newUrl) => {
        setUrl(newUrl);
        setAttempt(!attempt);
    }, [newUrl, attempt]);

    return [state, updateUrl];
};

或者检查是否可以简化以下内容。

const useDataApi = (initialUrl, initialData) => {
    const [state, dispatch] = useReducer(dataFetchReducer, {
        isLoading: false,
        isError: false,
        data: initialData,
    });

    const setUrl = useCallback((url) => {
        const fetchData = async () => {
            dispatch({ type: 'FETCH_INIT' });
            try {
                const result = await axios(url);
                dispatch({ type: 'FETCH_SUCCESS', payload: result.data });
            } catch (error) {
                dispatch({ type: 'FETCH_FAILURE' });
            }
        };
        fetchData();
    }, []);

    useEffect(() => setUrl(initialUrl), []);

    return [state, setUrl];
};