Ошибка (сгенерированный новый пустой список) после редактирования данных с помощью React, Redux и Redux Form - PullRequest
0 голосов
/ 10 февраля 2020

Я сталкиваюсь с проблемой при редактировании данных с реакцией и избыточностью. Проблема в , когда я go редактирую форму, затем отправляю, автоматизирую c создаю новый пустой список , как это (изображение ниже)

Error on empty list

Ошибка на консоли:

Предупреждение. У каждого дочернего элемента в списке должна быть уникальная «ключевая» опора.

Когда я проверяю базу данных , это нормально и не добавлять новые пустые данные. Также, когда я обновляю sh страницу, возвращаюсь к нормальному состоянию и без ошибок, и пустой список go прочь.

Вот некоторые из моего кода:

actions / cityActions. js

export const editCity = (id, formValues) => async dispatch => {
 const response = await ws.patch(`/api/cities/${id}`, formValues);
 dispatch({
  type: EDIT_CITY,
  payload: response.data
 });
 history.push("/");
};

компоненты / CityEdit. js

import _ from "lodash";
import React from "react";
import { connect } from "react-redux";
import { fetchCity, editCity } from "../../actions/cityActions";
import CityForm from "./CityForm";

class CityEdit extends React.Component {
  componentDidMount() {
    this.props.fetchCity(this.props.match.params.id);
  }
  onSubmit = formValues => {
    this.props.editCity(this.props.match.params.id, formValues);
  };
  render() {
    if (!this.props.city) {
      return <div>...</div>;
    }
    return (
      <div>
        <h3>Edit a City</h3>
        <CityForm
          initialValues={_.pick(this.props.city, "name", "description")}
          onSubmit={this.onSubmit}
        />
      </div>
    );
  }
}

const mapStateToProps = (state, ownProps) => {
  return { city: state.cities[ownProps.match.params.id] };
};

export default connect(mapStateToProps, { fetchCity, editCity })(CityEdit);

компоненты / CityForm. js

import React from "react";
import { Field, reduxForm } from "redux-form";

class CityForm extends React.Component {
  renderError({ error, touched }) {
    if (error && touched) {
      return (
        <div className="alert alert-danger mt-1" role="alert">
          {error}
        </div>
      );
    }
  }

  renderInput = ({ input, label, meta, type, rows }) => {
    const className = `field ${meta.error && meta.touched ? "error" : ""}`;
    return (
      <div className={className}>
        <label>{label}</label>
        <input
          className="form-control"
          {...input}
          autoComplete="off"
          type={type}
          rows={rows}
        />
        {this.renderError(meta)}
      </div>
    );
  };

  onSubmit = formValues => {
    this.props.onSubmit(formValues);
  };

  render() {
    return (
      <div>
        <form onSubmit={this.props.handleSubmit(this.onSubmit)}>
          <div className="form-group">
            <Field
              name="name"
              component={this.renderInput}
              label="City Name"
              type="text"
            />
          </div>
          <div className="form-group">
            <Field
              name="description"
              component={this.renderInput}
              label="Description"
              type="textarea"
              rows="7"
            />
          </div>

          <button className="btn btn-primary">Submit</button>
        </form>
      </div>
    );
  }
}

const validate = formValues => {
  const errors = {};
  if (!formValues.name) {
    errors.name = "You must add a name";
  }
  if (!formValues.description) {
    errors.description = "You must add a description";
  }
  return errors;
};

export default reduxForm({
  form: "cityForm",
  validate
})(CityForm);

редукторы / cityReducer. js

import _ from "lodash";
import {
  FETCH_CITY,
  FETCH_CITIES,
  CREATE_CITY,
  EDIT_CITY,
  DELETE_CITY
} from "../actions/types";

export default (state = {}, action) => {
  switch (action.type) {
    case FETCH_CITIES:
      return { ...state, ..._.mapKeys(action.payload, "_id") };
    case FETCH_CITY:
      return { ...state, [action.payload.id]: action.payload };
    case CREATE_CITY:
      return { ...state, [action.payload.id]: action.payload };
    case EDIT_CITY:
      return { ...state, [action.payload.id]: action.payload };
    case DELETE_CITY:
      return _.omit(state, action.payload);
    default:
      return state;
  }
};

полный код в моем github https://github.com/hidjrie/ws

Извините, мой плохой Engli sh, не стесняйтесь редактировать мой пост. Спасибо 10

1 Ответ

0 голосов
/ 10 февраля 2020

Прежде всего, сохраните некоторое начальное состояние внутри вашего редуктора. Затем вы должны рассмотреть полезную нагрузку, которую вы получаете от своего действия. Из звонка

const response = await ws.patch(`/api/cities/${id}`, formValues);

Проверьте, получаете ли вы только отредактированный документ / данные в качестве выходных данных или весь массив городов, который включает новые данные. Если вы получаете только данные для редактирования города, то вам нужно найти город из массива city внутри редуктора и отредактировать его. Если нет, вы можете просто заменить весь массив на новый массив городов, возвращаемый базой данных. Но, просматривая исходный код в Github, похоже, что из оставшегося вызова City Update вы не возвращаете массив данных, а возвращаете что-то вроде
{ "acknowledged" : true, "matchedCount" : 1, "modifiedCount" : 1 }, которое не содержит ни идентификатора, ни данных. Поэтому, когда вы получаете эти данные, они добавляются к ним, и поэтому в массиве вашего города будет объект, который не имеет никакого свойства, например, id name et c. Поэтому вы получите любую запись о городе в вашем списке, которая будет пустой.

Для этого попробуйте изменить updateOne на findByIdAndUpdate с флагом {lean: true}. Это вернет объект. и убедитесь, что вы внесли необходимые изменения в свой редуктор, чтобы справиться с этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...