useReducer() 正在为一个组件返回数据,而对于其他组件,它正在返回 initialState

useReducer() is returning data for one component and for other component it is returning the initialState

我实际上有 2 个组件需要来自具有某种状态的减速器的数据。 CurrentWeather 组件以非常高的级别显示天气,而 CurrentWeatherDetailed 以详细的方式显示天气。第一个先渲染,如果点击 Details 它将渲染 CurrentWeatherDetailedCurrentWeather 调度一个操作来获取一些数据并使用该数据更新状态,稍后它通过 useReducer 获取状态并按预期呈现来自该状态的数据。另一方面,CurrentWeatherDetailed 也尝试获取当前填充的状态,但它只是 returns null(即 initialState)而不是什么实际上在状态下,考虑到 CurrentWeather,我假设;已经改变了状态。所以我已经尝试了很多,但我还没有找到为什么会发生这种情况的解释。

这是减速器:

export const initialState = {
    loading: false,
    error: null,
    data: null,
}

const weatherRequestReducer = (state = initialState, action) => {
    switch (action.type) {
        case 'SEND':
            return {...state,
                loading: true,
                error: null,
                data: null,
            };
        case 'RESPONSE':
            console.log(state);
            console.log(action.responseData);
            return {...state,
                loading: false,
                data: action.responseData
            };
        case 'ERROR':
            return {...state,
                loading: false,
                error: action.errorMessage,
                data: null
            };
        case 'CLEAR-ERROR':
            return {...state,
                error:null
            };
        default:
            return state;
            // throw new Error('Should not get there')
    }
}

export default weatherRequestReducer;

这是一个使用 reducer 生成状态并将其 return 发送到其他组件的钩子:

import {useReducer, useCallback, useState, useEffect} from 'react';
import weatherRequestReducer from "../reducers/weatherRequestReducer";
import {initialState} from "../reducers/weatherRequestReducer";
import api from '../utils/WeatherApiConfig'

const useCurrentWeather = () => {

    const [weatherRequestState, dispatchWeatherRequestActions] = useReducer(weatherRequestReducer, initialState);


    const sendRequestToGetCurrentWeather = useCallback(() => {
        dispatchWeatherRequestActions({type: 'SEND'});

         const uri = 'weather?q=London,uk';
         api.get(uri)
             .then(res => {
                 const responseData = res.data;
                 console.log(responseData.base);
                 dispatchWeatherRequestActions({type: 'RESPONSE', responseData: responseData});
             })
             .catch(err => {
                 console.log(err);
                 dispatchWeatherRequestActions({type: 'ERROR', errorMessage: 'Something went wrong!'});
             });
    }, []);


    return {
        getCurrentWeatherPointer: sendRequestToGetCurrentWeather,
        isLoading: weatherRequestState.loading,
        error: weatherRequestState.error,
        data: weatherRequestState.data,
    }
}

export default useCurrentWeather;

这是调用 CurrentWeatherCurrentWeatherDetailedApp 组件,具体取决于虚拟状态:

import CurrentWeather from "./components/CurrentWeather/CurrentWeather";
import CurrentWeatherDetailed from "./components/CurrentWeather/CurrentWeatherDetailed";
import {useState} from "react";
import weatherRequestReducer from "./reducers/weatherRequestReducer";

function App() {

    const [state, setState] = useState(0);

    const renderComponent = () => {
        setState(1)
    }

    let comp = <CurrentWeather renderComponent={renderComponent}/>;
    if(state === 1){
        comp = <CurrentWeatherDetailed/>
    }

    return {comp}
}

export default App;

以下组件工作正常,console.log(data) 显示了请求的实际数据。

import React, {useEffect} from 'react';
import useCurrentWeather from "../../hooks/useCurrentWeather";


const CurrentWeather = (props) => {

    const {getCurrentWeatherPointer, isLoading, error, data} = useCurrentWeather();

    useEffect(() => {
        getCurrentWeatherPointer();
    }, [getCurrentWeatherPointer])

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

    const displayDetails = () => {
        props.renderComponent();
    }

    return ( <Some JSX>
                <div className={classes.buttonContainer}>
                    <button onClick={displayDetails}>Details →</button>
                </div>
             <Some JSX> );
}

export default CurrentWeather;

这是失败的组件,因为正在获取数据 null 而不是 CurrentWeather 组件已经获取的数据:

import React, {useEffect} from 'react';
import useCurrentWeather from "../../hooks/useCurrentWeather";

const CurrentWeatherDetailed = (props) => {

    const {getCurrentWeatherPointer, isLoading, error, data} = useCurrentWeather();

    useEffect(() => {
        console.log(data)
        setTimeout(() => {console.log(data);}, 500 );
    }, [data])

    return ( <Some JSX> );
}

export default CurrentWeatherDetailed;

如果我只是将 useEffect(() => {getCurrentWeatherPointer();},[getCurrentWeatherPointer]) 添加到 CurrentWeatherDetailed,它可以正常工作 CurrentWeather,但是,我不想这样做,因为我已经从 API 到 reducer 状态,所以再次加载它没有意义,而是在调用这个详细组件时使用已经存在的内容。

有人知道为什么会这样吗?

在此先感谢大家。

发生这种情况的原因是您一次只渲染一个组件,并且您的 组件是彼此的同级 。当您的天气组件获取数据时,有 no weather details component 。因此,当您单击详细信息按钮时,您正在安装 CurrentWeatherDetailed,这意味着您正在从头开始创建组件。此时你的 CurrentWeatherDetailed 并不知道 CurrentWeather 做了什么,因为组件是相互隔离的,它们之间共享信息的唯一方式是通过 props 。所以你的 CurrentWeatherDetailed 再次初始化减速器。

您应该将 useReducer 移动到 App 并将其从 CurrentWeatherDetailedCurrentWeather 中删除。这样您就可以在 CurrentWeatherDetailedCurrentWeather 之间共享信息。

function App() {
  const [state, setState] = useState(0);
  const {getCurrentWeatherPointer, isLoading, error, data} = useCurrentWeather();

  const renderComponent = () => {
    setState(1);
  };

  let comp = <CurrentWeather renderComponent={renderComponent} getCurrentWeatherPointer={getCurrentWeatherPointer}/>;
  if (state === 1) {
    comp = <CurrentWeatherDetailed data={data} />;
  }

  return {comp};
}

export default App;

你有一个误解: useReducer 不会 在组件上共享状态。它就像 useState React 的一部分,仅用于本地组件状态。
数据不在“reducer”中共享(这只是一个函数),它仅使用 reducer 来描述基于您调度的操作的状态转换。

如果您希望这些数据在组件之间共享,您必须将其向上移动到一个共同的父级,然后使用 props 或上下文将其传递给所有需要它的子级,或者只使用像 Redux 这样的全局状态管理解决方案。