useReducer() 正在为一个组件返回数据,而对于其他组件,它正在返回 initialState
useReducer() is returning data for one component and for other component it is returning the initialState
我实际上有 2 个组件需要来自具有某种状态的减速器的数据。 CurrentWeather
组件以非常高的级别显示天气,而 CurrentWeatherDetailed
以详细的方式显示天气。第一个先渲染,如果点击 Details 它将渲染 CurrentWeatherDetailed
。 CurrentWeather
调度一个操作来获取一些数据并使用该数据更新状态,稍后它通过 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;
这是调用 CurrentWeather
和 CurrentWeatherDetailed
的 App
组件,具体取决于虚拟状态:
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
并将其从 CurrentWeatherDetailed
和 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;
你有一个误解:
useReducer
不会 在组件上共享状态。它就像 useState
React 的一部分,仅用于本地组件状态。
数据不在“reducer”中共享(这只是一个函数),它仅使用 reducer 来描述基于您调度的操作的状态转换。
如果您希望这些数据在组件之间共享,您必须将其向上移动到一个共同的父级,然后使用 props 或上下文将其传递给所有需要它的子级,或者只使用像 Redux 这样的全局状态管理解决方案。
我实际上有 2 个组件需要来自具有某种状态的减速器的数据。 CurrentWeather
组件以非常高的级别显示天气,而 CurrentWeatherDetailed
以详细的方式显示天气。第一个先渲染,如果点击 Details 它将渲染 CurrentWeatherDetailed
。 CurrentWeather
调度一个操作来获取一些数据并使用该数据更新状态,稍后它通过 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;
这是调用 CurrentWeather
和 CurrentWeatherDetailed
的 App
组件,具体取决于虚拟状态:
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
并将其从 CurrentWeatherDetailed
和 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;
你有一个误解:
useReducer
不会 在组件上共享状态。它就像 useState
React 的一部分,仅用于本地组件状态。
数据不在“reducer”中共享(这只是一个函数),它仅使用 reducer 来描述基于您调度的操作的状态转换。
如果您希望这些数据在组件之间共享,您必须将其向上移动到一个共同的父级,然后使用 props 或上下文将其传递给所有需要它的子级,或者只使用像 Redux 这样的全局状态管理解决方案。