为啥 useSelector 不包含任何数据?
Posted
技术标签:
【中文标题】为啥 useSelector 不包含任何数据?【英文标题】:Why useSelector does not contain any data?为什么 useSelector 不包含任何数据? 【发布时间】:2021-04-02 15:19:48 【问题描述】:我是 React-redux-hooks 的新手。我的目标是在单击按钮时将 inputView.js 中的数据带入 temperatureView.js。
这是我的一些代码,
我在inputView.js
内部初始化useSelector
和useDispatch
const temperatureSelector=useSelector(state=>state.temperatureInfo)
const dispatch = useDispatch();
...
const handleClick = (e) =>
e.preventDefault();
dispatch(getTemperature());
history.push(
pathname: '/temperatureView',
state: params: temperatureSelector
)
当我登录到 temperatureView.js 时,它什么也没有。我是否错误地使用了 useSelector?或者也许使用调度? 还是我应该在 useEffect 内部调度?
如何做到这一点?
编辑
actions/index.js
export const getTemperature = (city) =>
return async function(dispatch)
await fetch("myhttp").then(res =>
return res.json();
).then(resJOSN =>
dispatch(type: "GET_TEMPERATURE", payload: resJOSN)
).catch(err =>
console.log(err);
)
reducers/index.js
import combineReducers from 'redux';
const temperatureinfo = (state =
temperatureinfo:
, action) =>
if(action.type === "GET_TEMPERATURE")
state = ...state, temperatureInfo:action.payload
return state
const reducers = combineReducers (
temperatureInfo:temperatureinfo,
)
export default reducers;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './view/App';
import reportWebVitals from './reportWebVitals';
import Provider from 'react-redux';
import createStore, applyMiddleware from 'redux';
import reducers from './reducers';
import thunk from 'redux-thunk';
ReactDOM.render(
<Provider store=createStore(reducers, applyMiddleware(thunk))><App /></Provider>,
document.getElementById('root')
);
reportWebVitals();
App.js
import TemperatureView from './TemperatureView';
import InputView from './InputView';
function App(props)
return (
<div>
<BrowserRouter>
<Route path="/" exact component=InputView />
<Route path="/temperatureView" component=TemperatureView/>
</BrowserRouter>
</div>
);
export default App;
InputView.js
import React, useEffect from 'react';
import makeStyles from '@material-ui/core/styles';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import Select from '@material-ui/core/Select';
import FormControl from '@material-ui/core/FormControl';
import Input from '@material-ui/core/Input';
import Button from '@material-ui/core/Button';
import useHistory from "react-router-dom";
import useSelector, useDispatch from 'react-redux';
import getTemperature from '../actions';
const useStyles = makeStyles((theme) => (
root:
'& > *':
margin: theme.spacing(1),
,
,
));
function InputView(props)
const history = useHistory();
const classes = useStyles();
const City = [
"id": "YG", "name": 'Yangon',
"id": "NY", "name": 'New York'
];
const [state, setState] = React.useState(
apiKey: '123',
cityName: 'NY'
);
const temperatureSelector=useSelector(state=>state.temperatureInfo)
const dispatch = useDispatch();
const handleChange = (event) =>
const name = event.target.name;
setState(
...state,
[name]: event.target.value,
);
;
const handleChange1 = (event) =>
const name = event.target.name;
setState(
...state,
[name]: event.target.value,
);
;
const handleClick = (e) =>
e.preventDefault();
dispatch(getTemperature());
history.push(
pathname: '/temperatureView',
state: params: temperatureSelector
)
useEffect(()=>
console.log('mounted');
return () => console.log('unmounting...');
,[]
);
return (
<div style=display: "flex", height:"100vh", alignItems:"center", justifyContent:"center" >
<form className=classes.root noValidate autoComplete="off">
<div style=marginTop:"40px", marginBottom:"40px">
<FormControl>
<InputLabel htmlFor="input-form" style=color:"red">Your API Key</InputLabel>
<Input id="input-form" value=state.apiKey name="apiKey" onChange=handleChange style=width:"300px" />
</FormControl>
</div>
<div style=marginTop:"40px", marginBottom:"40px">
<FormControl className=classes.formControl>
<InputLabel shrink id="button-file" style=color:"red">
City Name
</InputLabel>
<Select
labelId="button-file"
id="button-file"
value = state.cityName
displayEmpty
name="cityName"
onChange=handleChange1
style=width:"300px"
>
<MenuItem key=City[0].id value=City[0].id>
City[0].name
</MenuItem>
<MenuItem key=City[1].id value=City[1].id>
City[1].name
</MenuItem>
</Select>
</FormControl>
</div>
<div style=marginTop:"100px", marginBottom:"100px">
<Button type="submit" htmlFor="button-file" variant="contained" color="secondary" fullWidth=true onClick=handleClick >Submit</Button>
</div>
</form>
</div>
);
export default InputView;
TemperatureView.js
import React from 'react';
import Typography from '@material-ui/core/Typography';
import TextField from '@material-ui/core/TextField';
function TemperatureView(props)
return <div style=marginTop: "80px", marginLeft: "40px">
<Typography color="error" >
Celcius
</Typography>
<TextField
id="celcius"
defaultValue="23.5"
InputProps=
readOnly: true,
/>
<Typography color="error" >
Fahrenheit
</Typography>
<TextField
id="fahrenheit"
defaultValue="2234"
InputProps=
readOnly: true,
/>
</div>
export default TemperatureView;
【问题讨论】:
我认为需要更多关于你的减速器和动作的信息。 视情况而定。您是否尝试在组件安装时调度以获取温度(供以后使用,即当用户单击某物时)?或者更确切地说,您似乎正在尝试调度一个操作来获取温度,然后在temperatureSelector
值更新之前立即离开当前页面,存储当前值处于路由状态的任何内容。
您能否更新您的问题以包含此组件的Minimal, Complete, and Reproducible 代码示例和您尝试访问路由状态的组件?您能否谈谈您想要和期望代码做什么,以便我们了解您的用例并提供更好的帮助?
@DrewReese 我已经用所有代码更新了我的问题。我的目标是在用户单击按钮后我想稍后使用。我想在下一页显示。
@WonGyoSeo 我更新了代码。
【参考方案1】:
把你的动作放在useEffect
里面,你必须触发动作
useEffect(() =>
dispatch(getTemperature());
, []);
【讨论】:
我收到警告,``` React Hook useEffect 缺少依赖项:'dispatch'。要么包含它,要么移除依赖数组 react-hooks/exhaustive-deps``` 你可以忽略警告 忽略警告而不理解为什么不是一个好习惯。【参考方案2】:问题
-
您不会派出一个城市来测量温度。
您会立即导航到“/temperatureView”,而 just 调度的操作仍在处理中,因此
temperatureSelector
的状态尚未更新。
解决方案 0 - 完成时获取临时和导航的调度操作
创建一个全局历史对象,您可以从异步操作中分派导航操作。提交表单后,只需发送操作。当提取解析到目标路径的导航完成并且应用导航到具有路由状态负载的页面时。
App.js
使用常规的Router
代替BrowserRouter
,这样您就可以使用自己的history
对象。从history
包中创建一个history
对象。
import Router from 'react-router-dom';
import createBrowserHistory from 'history';
...
export const history = createBrowserHistory()
function App(props)
return (
<div>
<Router history=history>
...
</Router>
</div>
);
动作
fetch
返回一个 Promise
并且您已经从它链接,因此无需声明函数 async
和 await
获取分辨率。当提取解析和导航可以发生时。以路由状态传递响应对象。
import history from '/path/to/app.js';
export const getTemperature = (city) =>
return function(dispatch)
fetch("myhttp")
.then(res => res.json())
.then(resJOSN =>
dispatch( type: "GET_TEMPERATURE", payload: resJOSN );
history.push(
pathname: '/temperatureView',
state:
temperatureSelector: resJOSN,
,
);
)
.catch(err =>
console.log(err);
);
InputView.js
更新处理程序以将state.cityName
传递给getTemperature
操作。
const handleClick = (e) =>
e.preventDefault(); // <-- prevent default form action
dispatch(getTemperature(state.cityName)); // <-- pass city
修复表单提交按钮。它已经在表单中,因此不需要onClick
处理程序。处理程序应附加到表单的onSubmit
处理程序。
return (
...
<form
className=classes.root
noValidate autoComplete="off"
onSubmit=handleClick
>
...
<Button
type="submit" // <-- will submit the form when clicked!
variant="contained"
color="secondary"
fullWidth=true
>
Submit
</Button>
</form>
...
);
TemperatureView.js
使用useLocation
钩子访问路由状态。
import React from 'react';
import useLocation from 'react-router-dom';
...
function TemperatureView(props)
const state: temperatureSelector = useLocation(); // <-- access route state
return (
...
);
解决方案 1 - 调度操作以获取温度并立即导航
调度操作以获取城市温度并立即导航到新页面。该页面订阅了您的 redux 存储并“等待”状态更新。
InputView.js
与上面相同的更新,但也可以导航。删除temperatureSelector
行,这将在别处访问。
const handleClick = (e) =>
e.preventDefault(); // <-- prevent default form action
dispatch(getTemperature(state.cityName)); // <-- pass city
history.push('/temperatureView'); // <-- navigate immediately
动作
与上述相同的更改,但没有 history
导入和导航操作。
export const getTemperature = (city) =>
return function(dispatch)
fetch("myhttp")
.then(res => res.json())
.then(resJOSN =>
dispatch( type: "GET_TEMPERATURE", payload: resJOSN );
)
.catch(err =>
console.log(err);
);
TemperatureView.js
使用 useSelector
钩子访问 redux 状态。请记住在获取城市温度并将其填充到状态时执行任何条件渲染(即“...加载”)。
import React from 'react';
...
function TemperatureView(props)
const temperatureSelector = useSelector(state => state.temperatureInfo);
return (
...
);
【讨论】:
以上是关于为啥 useSelector 不包含任何数据?的主要内容,如果未能解决你的问题,请参考以下文章
Redux,使用 useSelector 访问 API 对象内的数据