【问题标题】:React/Redux Doesn't Update State Properly and Can't Be Used in ComponentReact/Redux 不能正确更新状态,不能在组件中使用
【发布时间】:2020-01-14 05:43:42
【问题描述】:

我是 React 和 Redux 的新手,一直在关注官方 Redux 文档 Todo List 示例https://redux.js.org/basics/example,最近更改了我的代码以遵循演示/容器组件结构。我尝试了许多不同的方法来移动 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;
  }
}

组件/项目/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

组件/项目/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 组件(我没有显示,因为它工作正常并正确更新状态,但如果需要显示上下文,肯定可以添加)。

容器/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)

如果我可以添加任何其他代码或 cmets,请告诉我。在过去的两天里,我一直在努力解决这个小问题,但无法弄清楚需要进行哪些更改才能使其正常工作。我知道 API 被正确调用,但不知道需要如何更改组件才能正确显示它。 **当我尝试调用组件而不是组件时,出现错误:'TypeError: Cannot read property 'map' of undefined' **

【问题讨论】:

  • components/Items/index.js 中,您将weights 解构为对象,但初始状态您将其声明为空数组

标签: reactjs redux react-redux material-ui connect


【解决方案1】:

正如您在 reducers/weights.js 的初始状态中将 weights 声明为空数组 []

你正在解构它,如下所示

const { weights } = this.props.weights;

根据您的声明,权重是undefined,您会收到错误消息

TypeError: Cannot read property 'map' of undefined

所以请尝试根据您的确切要求进行更改

确保您的所有代码即使在没有数据的情况下也能正常工作,因为整个组件在 API 调用之前已被渲染,因此要么处理组件以使用空数据渲染,并确保您的代码在获取 API 数据之前不会出现故障

根据您的代码,它认为 wights 是对象数组,因此我认为进行以下更改不会破坏您的应用程序

文件components/Items/index.js

render 函数中更改以下行

const { weights } = this.props.weights;

const { weights = [] } = this.props;

【讨论】:

  • 感谢您的评论,感谢您的快速回复!但是,此更改仍然不允许显示 VisibleWeights 组件而不是 WeightItems 组件。我没有从我显示的代码中得到未定义的 TypeError,但是在 components/Items/index.js 中用 VisibleWeights 替换 WeightItems 组件时确实得到它
  • 能否为应用创建一个codeandbox以便更好地调试
  • 是的,我会尝试在今天的某个时间组装一个,感谢您的帮助!
  • 哇,在创建代码沙箱的过程中,我意识到我正在映射的返回对象有一个同名的子组件,其中包含数据库中的每个数据数组。即使没有显示沙盒,你也让我找到了答案,我很感激!
猜你喜欢
  • 1970-01-01
  • 2020-08-12
  • 1970-01-01
  • 1970-01-01
  • 2019-06-13
  • 2021-03-19
  • 2019-12-29
  • 2019-08-18
  • 1970-01-01
相关资源
最近更新 更多