React/Redux 状态更新不正确,无法在组件中使用
React/Redux Doesn't Update State Properly and Can't Be Used in Component
我是 React 和 Redux 的新手,一直在关注官方 Redux 文档待办事项列表示例 https://redux.js.org/basics/example,最近更改了我的代码以遵循 presentational/container 组件结构。我已经尝试了许多不同的方法来移动 API 调用,但是状态中的权重对象经常显示为未定义(可能是因为它试图在实际 API 调用之前被使用,但是我不知道如何从现在的位置更改 API 调用。
文件如下:
actions/index.js
import axios from 'axios';
export const getWeights = () => dispatch => {
axios.get('/api/weights')
.then(res =>
dispatch({
type: 'GET_WEIGHTS',
payload: res.data
})
)
}
export const setShownCategory = category => ({
type: 'SET_SHOWN_CATEGORY',
category
})
export const Categories = {
SHOW_ALL: 'SHOW_ALL',
SHOW_ACCESSORIES: 'SHOW_ACCESSORIES',
SHOW_BARBELLS: 'SHOW_BARBELLS',
SHOW_DUMBBELLS: 'SHOW_DUMBBELLS',
SHOW_PLATES: 'SHOW_PLATES',
SHOW_RACKS: 'SHOW_RACKS',
SHOW_OTHER: 'SHOW_OTHER'
}
reducers/weights.js
const initialState = {weights: []}
export default function(state = initialState, action) {
switch (action.type) {
case 'GET_WEIGHTS':
return {
...state,
weights: action.payload
}
default:
return state;
}
}
components/Items/index.js
import React from 'react';
import CategoryBar from './CategoryBar'
import Typography from '@material-ui/core/Typography';
import { connect } from 'react-redux';
import { getWeights } from '../../actions'
import WeightItems from './WeightItems';
class Items extends React.Component {
componentDidMount() {
console.log(this.props)
this.props.getWeights();
}
render() {
const { weights } = this.props.weights;
return (
<div>
<Typography variant="h4">Browse</Typography>
<div>
<CategoryBar />
</div>
<WeightItems weights={weights} />
</div>
)
}
}
const mapStateToProps = state => ({
weights: state.weights
});
export default connect(
mapStateToProps,
{ getWeights }
)(Items)
components/Items/WeightItems.js
import React from 'react'
import Grid from '@material-ui/core/Grid';
import { makeStyles } from '@material-ui/core/styles';
import Item from './Item'
const useStyles = makeStyles({
items: {
display: 'flex',
margin: 'auto',
}
})
const WeightItems = ({ weights }) => {
const classes = useStyles()
return (
<Grid className={classes.items} container direction="row" justify="center" alignItems="center" spacing={3}>
{weights.map(weight => <Item key={weight.id} weight={weight} />)}
</Grid>
)
}
export default WeightItems
components/Items/Item.js
import React from 'react';
import Paper from '@material-ui/core/Paper';
import Grid from '@material-ui/core/Grid';
const Item = ({ weight }) => {
return (
<Grid item xs={12} sm={6} md={4}>
<Paper>{weight.title}</Paper>
</Grid>
)
}
export default Item
store.js
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const initialState = {};
const middleWare = [thunk];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
rootReducer,
initialState,
composeEnhancers(applyMiddleware(...middleWare))
);
export default store;
目前,我通过导入相应的调度操作并使用 connect() 来调用 components/Items/index.js 组件中的 API,但是,我没有这样做并传递权重,而是需要能够在其他地方调用 API 并根据从不同组件中选择的过滤器呈现 VisibleWeights 组件(我没有显示它正常工作并正确更新状态,但绝对可以添加如果它需要显示上下文)。
containers/VisibleWeights.js
import { connect } from 'react-redux'
import { Categories } from '../actions'
import WeightItems from '../components/Items/WeightItems'
const getVisibleWeights = (weights, category) => {
console.log(weights, category)
switch(category) {
case Categories.SHOW_ACCESSORIES:
return weights.filter(weight => weight.category === 'Accessories')
case Categories.SHOW_BARBELLS:
return weights.filter(weight => weight.category === 'Barbells')
case Categories.SHOW_DUMBBELLS:
return weights.filter(weight => weight.category === 'Dumbbells')
case Categories.SHOW_PLATES:
return weights.filter(weight => weight.category === 'Plates')
case Categories.SHOW_RACKS:
return weights.filter(weight => weight.category === 'Racks')
case Categories.SHOW_OTHER:
return weights.filter(weight => weight.category === 'Other')
}
}
const mapStateToProps = state => ({
weights: getVisibleWeights(state.weights, state.shownCategory)
})
export default connect(
mapStateToProps,
)(WeightItems)
如果我可以添加任何其他代码或评论,请告诉我。在过去的两天里,我一直在努力让这件小事变得正确,但无法弄清楚需要改变什么才能使它正常工作。我知道 API 被正确调用,但不知道如何更改组件才能正确显示它。 **当我尝试调用组件而不是组件时,出现错误:'TypeError: Cannot read 属性 'map' of undefined' **
正如您在 reducers/weights.js
中将 weights
声明为处于初始状态的空数组 []
你正在解构它,如下所示
const { weights } = this.props.weights;
因为您声明的权重是 undefined
您收到错误
TypeError: Cannot read property 'map' of undefined
所以尝试根据您的具体要求进行更改
确保您的所有代码即使在没有数据的情况下也能正常工作,因为整个组件在 API 调用之前渲染,因此要么处理组件以使用空数据渲染并确保您的代码不会在您之前 beak获取 API 数据
根据您的代码,它认为 wights
是对象数组,因此进行以下更改不会破坏您的应用程序,我认为
文件: components/Items/index.js
在render
函数中更改以下行
const { weights } = this.props.weights;
到
const { weights = [] } = this.props;
我是 React 和 Redux 的新手,一直在关注官方 Redux 文档待办事项列表示例 https://redux.js.org/basics/example,最近更改了我的代码以遵循 presentational/container 组件结构。我已经尝试了许多不同的方法来移动 API 调用,但是状态中的权重对象经常显示为未定义(可能是因为它试图在实际 API 调用之前被使用,但是我不知道如何从现在的位置更改 API 调用。
文件如下:
actions/index.js
import axios from 'axios';
export const getWeights = () => dispatch => {
axios.get('/api/weights')
.then(res =>
dispatch({
type: 'GET_WEIGHTS',
payload: res.data
})
)
}
export const setShownCategory = category => ({
type: 'SET_SHOWN_CATEGORY',
category
})
export const Categories = {
SHOW_ALL: 'SHOW_ALL',
SHOW_ACCESSORIES: 'SHOW_ACCESSORIES',
SHOW_BARBELLS: 'SHOW_BARBELLS',
SHOW_DUMBBELLS: 'SHOW_DUMBBELLS',
SHOW_PLATES: 'SHOW_PLATES',
SHOW_RACKS: 'SHOW_RACKS',
SHOW_OTHER: 'SHOW_OTHER'
}
reducers/weights.js
const initialState = {weights: []}
export default function(state = initialState, action) {
switch (action.type) {
case 'GET_WEIGHTS':
return {
...state,
weights: action.payload
}
default:
return state;
}
}
components/Items/index.js
import React from 'react';
import CategoryBar from './CategoryBar'
import Typography from '@material-ui/core/Typography';
import { connect } from 'react-redux';
import { getWeights } from '../../actions'
import WeightItems from './WeightItems';
class Items extends React.Component {
componentDidMount() {
console.log(this.props)
this.props.getWeights();
}
render() {
const { weights } = this.props.weights;
return (
<div>
<Typography variant="h4">Browse</Typography>
<div>
<CategoryBar />
</div>
<WeightItems weights={weights} />
</div>
)
}
}
const mapStateToProps = state => ({
weights: state.weights
});
export default connect(
mapStateToProps,
{ getWeights }
)(Items)
components/Items/WeightItems.js
import React from 'react'
import Grid from '@material-ui/core/Grid';
import { makeStyles } from '@material-ui/core/styles';
import Item from './Item'
const useStyles = makeStyles({
items: {
display: 'flex',
margin: 'auto',
}
})
const WeightItems = ({ weights }) => {
const classes = useStyles()
return (
<Grid className={classes.items} container direction="row" justify="center" alignItems="center" spacing={3}>
{weights.map(weight => <Item key={weight.id} weight={weight} />)}
</Grid>
)
}
export default WeightItems
components/Items/Item.js
import React from 'react';
import Paper from '@material-ui/core/Paper';
import Grid from '@material-ui/core/Grid';
const Item = ({ weight }) => {
return (
<Grid item xs={12} sm={6} md={4}>
<Paper>{weight.title}</Paper>
</Grid>
)
}
export default Item
store.js
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const initialState = {};
const middleWare = [thunk];
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
rootReducer,
initialState,
composeEnhancers(applyMiddleware(...middleWare))
);
export default store;
目前,我通过导入相应的调度操作并使用 connect() 来调用 components/Items/index.js 组件中的 API,但是,我没有这样做并传递权重,而是需要能够在其他地方调用 API 并根据从不同组件中选择的过滤器呈现 VisibleWeights 组件(我没有显示它正常工作并正确更新状态,但绝对可以添加如果它需要显示上下文)。
containers/VisibleWeights.js
import { connect } from 'react-redux'
import { Categories } from '../actions'
import WeightItems from '../components/Items/WeightItems'
const getVisibleWeights = (weights, category) => {
console.log(weights, category)
switch(category) {
case Categories.SHOW_ACCESSORIES:
return weights.filter(weight => weight.category === 'Accessories')
case Categories.SHOW_BARBELLS:
return weights.filter(weight => weight.category === 'Barbells')
case Categories.SHOW_DUMBBELLS:
return weights.filter(weight => weight.category === 'Dumbbells')
case Categories.SHOW_PLATES:
return weights.filter(weight => weight.category === 'Plates')
case Categories.SHOW_RACKS:
return weights.filter(weight => weight.category === 'Racks')
case Categories.SHOW_OTHER:
return weights.filter(weight => weight.category === 'Other')
}
}
const mapStateToProps = state => ({
weights: getVisibleWeights(state.weights, state.shownCategory)
})
export default connect(
mapStateToProps,
)(WeightItems)
如果我可以添加任何其他代码或评论,请告诉我。在过去的两天里,我一直在努力让这件小事变得正确,但无法弄清楚需要改变什么才能使它正常工作。我知道 API 被正确调用,但不知道如何更改组件才能正确显示它。 **当我尝试调用组件而不是组件时,出现错误:'TypeError: Cannot read 属性 'map' of undefined' **
正如您在 reducers/weights.js
weights
声明为处于初始状态的空数组 []
你正在解构它,如下所示
const { weights } = this.props.weights;
因为您声明的权重是 undefined
您收到错误
TypeError: Cannot read property 'map' of undefined
所以尝试根据您的具体要求进行更改
确保您的所有代码即使在没有数据的情况下也能正常工作,因为整个组件在 API 调用之前渲染,因此要么处理组件以使用空数据渲染并确保您的代码不会在您之前 beak获取 API 数据
根据您的代码,它认为 wights
是对象数组,因此进行以下更改不会破坏您的应用程序,我认为
文件: components/Items/index.js
在render
函数中更改以下行
const { weights } = this.props.weights;
到
const { weights = [] } = this.props;