微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决useReducer() 正在为一个组件返回数据,而对于另一个组件,它正在返回 initialState

我实际上有 2 个组件需要来自具有某种状态的 reducer 的数据。 CurrentWeather 组件以非常高的级别显示天气,并以详细的方式显示 CurrentWeatherDetailed。第一个首先呈现,如果单击详细信息,它将呈现 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,};
        case 'RESPONSE':
            console.log(state);
            console.log(action.responseData);
            return {...state,loading: false,data: action.responseData
            };
        case 'ERROR':
            return {...state,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;

以下是调用 AppCurrentWeatherCurrentWeatherDetailed 组件,具体取决于虚拟状态:

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,data} = useCurrentWeather();

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

    return ( <Some JSX> );
}

export default CurrentWeatherDetailed;

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

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

提前谢谢各位。

解决方法

发生这种情况的原因是您一次只渲染一个组件,并且您的组件是彼此的兄弟。当您的天气组件获取数据时,有 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 不会通过组件共享状态。它类似于 React 的 useState 部分,仅用于本地组件状态。
数据不会在“reducer”(它只是一个函数)中共享,它仅使用 reducer 来描述基于您调度的操作的状态转换。

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。