首页 > 解决方案 > useReducer() 正在为一个组件返回数据,而对于另一个组件,它正在返回 initialState

问题描述

实际上,我有 2 个组件需要来自具有某种状态的减速器的数据。该CurrentWeather组件以非常高的水平和CurrentWeatherDetailed详细的方式显示天气。第一个首先渲染,如果单击 Details 它将渲染CurrentWeatherDetailedCurrentWeather调度一个动作来获取一些数据并使用该数据更新状态,稍后它通过 useReducer 获取状态并按预期呈现来自该状态的数据。另一方面,CurrentWeatherDetailed, 也尝试获取当前填充的状态,但它只是返回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 生成状态并将其返回给其他组件的钩子:

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;

这是App调用CurrentWeatherand的组件CurrentWeatherDetailed,具体取决于虚拟状态:

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 →&lt;/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]),但是,我不想这样做,因为我已经将它从 API 加载到 reducer 状态,所以再次加载它是没有意义的,但要使用已经存在的调用此详细组件时。CurrentWeatherDetailedCurrentWeather

有谁知道为什么会这样?

提前谢谢各位。

标签: reactjsreduxreact-stateuse-reducer

解决方案


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

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

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;

推荐阅读