useReducer() 更改的 属性 状态永远不会显示更改,即使这些更改已被分派

A property of the state changed by useReducer() is never displaying changes even when those are dispatched

我一直在使用 useReducer() 以便我可以在一些组件之间共享一些状态。在 requestReducer 中有一个 属性 称为 isLoading,其中 default/initial 状态设置为 false。有两个函数将操作分派给 reducer(initializeLoading:将 isLoading 更改为 true,以及 getRequestResponse:将 isLoading 更改回 false)。但是当 reducer 用来初始化加载的函数 -initializeLoading- 被 CallingComponent 调用时,它使用这些函数的指针来调用它们; useEffect 中的状态变化(它依赖于 requestState.isLoading),永远不会显示在控制台中,也不会在 useCurrentRequest 挂钩和 CallingComponent 中调用,什么时候应该被调用;因为在第一次调用 isLoading prop 时,从 false 变成 true,通过 SEND action.type。此外,当从 CallingComponent 调用 getRequestResponse 函数(启动 RESPONSE action.type => isLoading = false)时,它应该从truefalse,因此它也应该由应该捕获这些更改的 useEffect 显示。但是什么都没有发生,而是什么也没有显示。

这是 useCurrentRequestrequestReducer:

import {useReducer, useCallback, useEffect} from 'react';

export const initialState = {
    isLoading: false,
    data: null,
}

const requestReducer = (state = initialState, action) => {
    switch (action.type) {
        case 'SEND':
            return {...state,
                isLoading: true,
            };
        case 'RESPONSE':
            return {...state,
                isLoading: false,
                data: action.responseData
            };
        default:
            return state;
    }
}

//This is the hook with the logic that sets state using the reducer
const useCurrentRequest = () => {

    const [requestState, dispatchRequestActions] = useReducer(requestReducer, initialState);

    //The loading change of state is not displayed in the console
    useEffect(() => {
        console.log(requestState.isLoading);
    }, [requestState.isLoading]);

    const initializeLoading = useCallback(() => {
        dispatchRequestActions({type: 'SEND'});
        console.log(requestState);
    },[]);

    const getRequestResponse = useCallback(() => {
        //some call to an api happens here
        //Then the response is given using the reducer 
        dispatchRequestActions({type: 'RESPONSE', responseData: {someData:true}});
    }, []);

    return {
        initializeLoadingPointer: initializeLoading,
        getRequestResponsePointer: getRequestResponse,
        isLoading: weatherRequestState.isLoading,
        data: weatherRequestState.data,
    }
}

export default useCurrentRequest;

这里是 CallingComponent,它使用 useCurrentRequest 钩子提供的函数指针:

import {useEffect} from "react";
import useCurrentRequest from "../hooks/useCurrentRequest";

const CallingComponent = props => {
    const {initializeLoadingPointer, getRequestResponsePointer, isLoading} = useCurrentWeather();

    const getData = () => {
            initializeLoadingPointer();
            getRequestResponsePointer();
    };

    useEffect(() => {
        console.log(isLoading);
    }, [isLoading]);

    return (<button onClick={getData}>Get data</button>) 
}

问题基本上是单击 Get Data 按钮后没有显示任何内容,而应该在控制台中显示 truefalse 的顺序,因为 useEffect() 取决于 isLoading 并且那些函数发生变化 isLoading,但同样没有显示任何内容。

我将不胜感激。

谢谢! :)

我终于通过使用async-await解决了这个问题,问题是由于对那些正在修改reducer的函数的请求是同步发生的,所以只有在它们都完成后才会更新状态,并且函数那个叫他们的也已经结束了。所以我所做的是通过 de async-await 模式使用 promises 来阻止一些代码片段。基本上,我只修改了 useCurrentRequest() 钩子,用这个替换了这两个函数:

const useCurrentRequest = () => {

    const [requestState, dispatchRequestActions] = useReducer(requestReducer, initialState);

    useEffect(() => {
        console.log(requestState.isLoading);
    }, [requestState.isLoading]);

  const sendRequestAsync = useCallback(async (city) => {
    const query = `weather?q=${city}`;
    console.log(query);
    dispatchRequestActions({ type: "SEND" });

    try {
      const result = await fakeRequest();
      dispatchRequestActions({ type: "RESPONSE", responseData: result.data });
    } catch (error) {
      dispatchRequestActions({ type: "ERROR", errorMessage: error.message });
    }
  }, []);

  const fakeRequest = () => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve({ data: "data" });
      }, 1000);
    });
  };

    return {
        getRequestResponsePointer: sendRequestAsync,
        isLoading: weatherRequestState.isLoading,
        data: weatherRequestState.data,
    }
}

export default useCurrentRequest;

这样我就可以使用 useEffect() 挂钩看到更改。