react store 和 redux 的问题 - 显示正确,但编辑导致错误

Problem with react store and redux - shows properly but editing cause error

提问人:bigmacreact 提问时间:11/13/2023 更新时间:11/14/2023 访问量:60

问:

我正在创建基于 store 和 react redux 的 react 应用程序,它们从 json 文件中获取数据。我有一个问题,我创建了所有结构并且它显示正确,但是当我尝试编辑一些数据时,它显示错误:state.properties.map 不是一个函数 我不完全了解 store 和 redux 是如何工作的,这就是为什么我需要你的帮助来找到问题所在,你能帮我吗?

还原剂:

import { UPDATE_PROPERTY } from "./actions";
import data from "./data.json"; // Importuj dane z pliku data.json

const initialState = {
  properties: data, // Ustaw dane z data.json jako początkowy stan properties
};

const rootReducer = (state = initialState, action) => {
  switch (action.type) {
    case UPDATE_PROPERTY:
      const updatedProperties = state.properties.map((prop) =>
        prop.name === action.payload.name ? action.payload : prop
      );
      return { ...state, properties: updatedProperties };
    default:
      return state;
  }
};

export default rootReducer;

商店:

import { configureStore } from "@reduxjs/toolkit";
import rootReducer from "./reducers";

const store = configureStore({
  reducer: {
    data: rootReducer,
  },
});

export default store;

行动:

export const UPDATE_PROPERTY = 'UPDATE_PROPERTY';

export const updateProperty = (property) => ({
  type: UPDATE_PROPERTY,
  payload: property,
});

索引.js:

import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import store from "./store";
import App from "./App";

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

财产:

import React, { useState } from "react";
import { useDispatch } from "react-redux";
import TextField from "@material-ui/core/TextField";
import Checkbox from "@material-ui/core/Checkbox";
import FormControlLabel from "@material-ui/core/FormControlLabel";
import Autocomplete from "@material-ui/lab/Autocomplete";

import { updateProperty } from "./actions";

const Property = ({ property }) => {
  const dispatch = useDispatch();
  const [editedProperty, setEditedProperty] = useState(property);

  const handleBlur = () => {
    dispatch(updateProperty(editedProperty));
  };

  const handleChange = (event) => {
    const { name, value, type, checked } = event.target;
    const newValue = type === "checkbox" ? checked : value;

    setEditedProperty({
      ...editedProperty,
      [name]: newValue,
    });
  };

  return (
    <div>
      <h3>{property.name}</h3>
      {property.type === "text" && (
        <TextField
          name="value"
          value={editedProperty.value}
          onBlur={handleBlur}
          onChange={handleChange}
        />
      )}
      {property.type === "checkbox" && (
        <FormControlLabel
          control={
            <Checkbox
              name="value"
              checked={editedProperty.value}
              onBlur={handleBlur}
              onChange={handleChange}
            />
          }
          label="Check"
        />
      )}
      {property.type === "combobox" && (
        <Autocomplete
          options={property.options}
          name="value"
          value={editedProperty.value}
          onBlur={handleBlur}
          onChange={(event, newValue) => {
            handleChange({ target: { name: "value", value: newValue } });
          }}
          freeSolo
          renderInput={(params) => <TextField {...params} />}
        />
      )}
    </div>
  );
};

export default Property;

应用程序:

import React from "react";
import { useSelector } from "react-redux";
import Property from "./Property";
import Accordion from "@mui/material/Accordion";
import AccordionSummary from "@mui/material/AccordionSummary";
import AccordionDetails from "@mui/material/AccordionDetails";
 function App() {
  const properties = useSelector((state) => state.data.properties);

  const groupedProperties = {};

  properties.properties.forEach((property) => {
    if (!groupedProperties[property.group]) {
      groupedProperties[property.group] = [];
    }
    groupedProperties[property.group].push(property);
  });

  return (
    <div className="App">
      {Object.entries(groupedProperties).map(([groupName, groupProperties]) => (
        <Accordion key={groupName}>
          <AccordionSummary>{groupName}</AccordionSummary>
          <AccordionDetails>
            <div>
              {groupProperties.map((property) => (
                <Property key={property.name} property={property} />
              ))}
            </div>
          </AccordionDetails>
        </Accordion>
      ))}
    </div>
  );
}

export default App;

这就是我使用的所有组件,如果您看到(很可能是)我所做的一些不良做法或愚蠢的解决方案 - 如果您指出它们,我将不胜感激。

reactjs json react-redux 商店

评论

0赞 Drew Reese 11/14/2023
import data from "./data.json";- 这里的价值是什么?它似乎不是您和代码假设的数组。请编辑以澄清并制作更完整的最小可重复示例data

答:

0赞 hcharles25 11/13/2023 #1

默认情况下,属性未定义。.map 不能与 undefined 一起使用。

尝试使用它

const updatedProperties = state.properties ? state.properties.map((prop) =>
  prop.name === action.payload.name ? action.payload : prop
) : [];

评论

0赞 bigmacreact 11/13/2023
我确实尝试过这个,但我仍然遇到同样的错误
0赞 Drew Reese 11/14/2023 #2

基于组件中的代码App

const properties = useSelector((state) => state.data.properties);

const groupedProperties = {};

properties.properties.forEach((property) => {
  if (!groupedProperties[property.group]) {
    groupedProperties[property.group] = [];
  }
  groupedProperties[property.group].push(property);
});

看起来该值实际上是一个具有数组属性的对象。换句话说,是数组。state.data.propertiespropertiesproperties.properties

更新 to access 数组rootReducerdata.properties

const initialState = {
  properties: data.properties,
};

或将整个对象引用作为值传递。datainitialState

const initialState = data;

例:

import { UPDATE_PROPERTY } from "./actions";
import data from "./data.json";

const initialState = {
  properties: data.properties,
};
// Or
// const initialState = data;

const rootReducer = (state = initialState, action) => {
  const { type, payload } = action;

  switch (type) {
    case UPDATE_PROPERTY:
      return {
        ...state,
        properties: state.properties.map((prop) =>
          prop.name === payload.name ? payload : prop
        )
      };

    default:
      return state;
  }
};

export default rootReducer;