首页 > 解决方案 > REACT/REDUX 编辑item和添加item后key的两个问题

问题描述

我有两个问题。我会尽可能多地解释它。

  1. 我在我的代码中添加了项目编辑功能,不幸的是,当我接受更改时,我的项目并没有改变。add(几乎),remove 选项可以正常工作。但是,更新选项不会发送请求。

  2. 第二个问题是,在添加编辑元素功能的代码稍作更改后,我添加元素的代码有点坏了。完成表单并发送后,添加了元素,但添加了没有ID码的错误:Warning: Each child in a list should have a unique "key" prop.刷新页面后,问题消失,之前添加的项目已经有ID并正确显示。

问题 1

TaskDetail.js 组件

import React, { Component } from "react";
import { connect } from "react-redux";
import { getTask, updateTask } from "../../actions/tasks";
import { Redirect } from "react-router-dom";

class TaskDetail extends Component {
  constructor(props) {
    super(props);

    this.state = {
      title: "",
      description: "",
      date: "",
      hours: null,
    };
  }

  componentDidMount() {
    this.props.getTask(this.props.match.params.id);
    setTimeout(() => this.update(), 50);
  }

  update = () => {
    console.log("STATE UPDATE");
    const { title, description, date, hours } = this.props.task[0];
    this.setState({
      title: title,
      description: description,
      date: date,
      hours: hours,
    });
  };

  onChange = (e) => {
    this.setState({
      [e.target.name]: e.target.value,
    });
  };

  onSubmit = (e) => {
    console.log("UPDATE REQUEST");
    const task = {
      title: this.state.title,
      description: this.state.description,
      date: this.state.date,
      hours: this.state.hour,
    };
    this.props.updateTask(this.props.task.id, task);
  };

  render() {
    const { title, description, date, hours } = this.state;
    return (
      <div className="card mt-5">
        <div className="card-header">
          <span>ID: {this.props.match.params.id}</span>
        </div>
        <form
          className="card-body"
          onSubmit={this.props.updateTask.bind(
            this.props.match.params.id,
            this.state
          )}
        >
          <div className="form-group">
            <label>Title</label>
            <input
              type="text"
              className="form-control"
              name="title"
              onChange={this.onChange}
              value={title || ""}
            />
          </div>
          <div className="form-group">
            <label>Description</label>
            <textarea
              type="text"
              className="form-control"
              name="description"
              onChange={this.onChange}
              value={description || ""}
            />
          </div>
          <div className="date-hours-form">
            <div className="form-group">
              <label>Date</label>
              <input
                type="date"
                className="form-control"
                name="date"
                onChange={this.onChange}
                value={date || ""}
              />
            </div>
            <div className="form-group">
              <label>Hours</label>
              <input
                type="number"
                className="form-control"
                name="hours"
                onChange={this.onChange}
                value={hours || ""}
              />
            </div>
          </div>
          <div className="form-group">
            <button type="submit" className="btn btn-block btn-suc">
              EDIT TASK
            </button>
          </div>
        </form>
      </div>
    );
  }
}

const mapStateToProps = (state) => ({
  task: state.tasks.task,
  isLoading: state.tasks.isLoading,
});

export default connect(mapStateToProps, { getTask, updateTask })(TaskDetail);

任务Action.js

// UPDATE TASK
export const updateTask = (id, task) => (dispatch) => {
  console.log(`ID: ${id} TASK: ${task}`);
  axios
    .put(`/api/tasks/${id}/`, task)
    .then((response) => {
      dispatch({
        type: UPDATE_TASK,
        payload: task,
      });
    })
    .catch((err) => console.log(err.response));
};

任务归约器.js

import {
  GET_TASKS,
  DELETE_TASK,
  CREATE_TASK,
  GET_TASK_REQUEST,
  GET_TASK_SUCCESS,
  UPDATE_TASK,
} from "../actions/types.js";

const initialState = {
  tasks: [],
  task: {},
  isLoading: false,
};

export default function (state = initialState, action) {
  switch (action.type) {
    case GET_TASKS:
      return {
        ...state,
        tasks: action.payload,
      };
    case DELETE_TASK:
      return {
        ...state,
        tasks: state.tasks.filter((task) => task.id !== action.payload),
      };
    case CREATE_TASK:
      return {
        ...state,
        tasks: [...state.tasks, action.payload],
      };
    case GET_TASK_REQUEST:
      console.log("TASK GET PENDING");
      return {
        ...state,
        isLoading: action.payload.loading,
      };
    case GET_TASK_SUCCESS:
      console.log("TASK GET SUCCESS");
      return {
        ...state,
        task: state.tasks.filter((task) => task.id === action.payload.data.id),
        isLoading: action.payload.loading,
      };
    case UPDATE_TASK:
      console.log("TASK UPDATED");
      return {
        ...state,
        task: {},
      };
    default:
      return state;
  }
}

问题二

任务列表.js

import React, { Component, Fragment } from "react";
import { connect } from "react-redux";
import { getTasks, deleteTask, getTask } from "../../actions/tasks";
import PropTypes from "prop-types";
import { Link } from "react-router-dom";

export class Tasks extends Component {
  static propTypes = {
    tasks: PropTypes.array.isRequired,
    getTasks: PropTypes.func.isRequired,
    deleteTask: PropTypes.func.isRequired,
  };

  render() {
    return (
      <div className="card card-tasks card-body mt-3">
        <table className="table table-striped">
          <thead>
            <tr>
              <th scope="col">ID</th>
              <th scope="col">Title</th>
              <th scope="col">Date</th>
              <th scope="col">Hours</th>
              <th scope="col"></th>
              <th scope="col"></th>
            </tr>
          </thead>
          <tbody>
            {this.props.tasks.map((task) => (
              <Fragment key={task.id}>
                <tr>
                  <th>{task.id}</th>
                  <td>{task.title}</td>
                  <td>{task.date}</td>
                  <td>{task.hours}</td>
                  <td>
                    <Link
                      to={{
                        pathname: `/edit/${task.id}`,
                        state: { id: task.id },
                      }}
                      className="btn btn-primary"
                    >
                      DETAIL
                    </Link>
                  </td>
                  <td>
                    <button
                      onClick={this.props.deleteTask.bind(this, task.id)}
                      className="btn btn-danger"
                    >
                      DELETE
                    </button>
                  </td>
                </tr>
              </Fragment>
            ))}
          </tbody>
        </table>
      </div>
    );
  }
}

const mapStateToProps = (state) => ({
  tasks: state.tasks.tasks,
});

export default connect(mapStateToProps, { getTasks, deleteTask, getTask })(
  Tasks
);

标签: javascriptreactjsreduxreact-redux

解决方案


推荐阅读