简体   繁体   English

在setState()之后反映渲染已删除的数组元素

[英]React rendering deleted array element after setState()

I'm having an issue where React seems to be rendering a deleted array element after I've removed it from an array in the components state. 我有一个问题,在我从组件状态的数组中删除它后,React似乎正在渲染一个已删除的数组元素。 After setState(), rendering is triggered, but the deleted item is shown, instead of the remaining item (see GIF video below). 在setState()之后,触发渲染,但会显示已删除的项目,而不是剩余的项目(请参阅下面的GIF视频)。

Although the component is extremely simple and I've spent hours on this problem, I haven't been able to solve this issue. 虽然组件非常简单,我花了几个小时来解决这个问题,但我还是无法解决这个问题。 The strange thing is that the newState object actually contains the valid new list, but it's not rendered. 奇怪的是,newState对象实际上包含有效的新列表,但它没有被渲染。

I really hope someone can help me figure this out! 我真的希望有人可以帮我解决这个问题!

GIF视频显示问题

import React from "react";
import Button from "@material-ui/core/Button";
import update from "immutability-helper";
import Grid from "@material-ui/core/Grid";
import TextField from "@material-ui/core/TextField";
import * as R from "ramda";

class SessionNoteGroup extends React.Component {
  state = {
    id: this.props.id,
    notes: this.props.notes
  };

  render() {
    const { classes } = this.props;

    const { id, notes } = this.state;

    return (
      <div>
        <Grid container>
          <Grid item xs={12}>
            <TextField
              multiline
              fullWidth
              id="notes"
              name="notes"
              label="Notes"
              rows="2"
              value={notes}
              onChange={this.handleValueChange}
            />
          </Grid>
        </Grid>
        <Button variant="outlined" color="primary" onClick={this.handleDelete}>
          Delete
        </Button>
      </div>
    );
  }

  handleValueChange = event => {
    const { name, value } = event.target;
    const { id, notes } = this.state;

    let newState = {
      id: id,
      notes: value
    };

    this.setState(newState);
  };

  handleDelete = () => {
    this.props.onDelete(this.state.id);
  };
}

class SessionNotes extends React.Component {
  state = {
    notes: this.props.notes.slice(),
    deleted: []
  };

  next_id = 2;

  createNotes = () => {
    let notesList = [];
    for (let i = 0; i < this.state.notes.length; i++) {
      const { id, notes } = this.state.notes[i];
      notesList.push(
        <SessionNoteGroup
          id={id}
          notes={notes}
          onDelete={this.handleDelete}
          index={i + 1}
        />
      );
    }
    console.log(notesList);
    return notesList;
  };

  handleDelete = id => {
    const newNotes = R.filter(note => note.id !== id, this.state.notes);
    this.setState({ notes: newNotes });
  };

  handleClickAdd = async () => {
    const note = {
      id: this.next_id,
      notes: ""
    };
    this.next_id++;
    const newState = update(this.state, { notes: { $push: [note] } });
    this.setState(newState);
  };

  render() {
    return (
      <div>
        {this.createNotes()}
        <Button
          variant="outlined"
          color="primary"
          onClick={this.handleClickAdd}
        >
          Add
        </Button>
      </div>
    );
  }
}

export default SessionNotes;

Few things. 一些事情。

When you want to set the state, based on the prev state, use the setState with a callback, which takes as argument the prevState. 如果要根据prev状态设置状态,请使用带有回调的setState ,该回调将prevState作为参数。 So the next code: 那么下一个代码:

handleValueChange = event => {
    const { name, value } = event.target;
    const { id, notes } = this.state;

    let newState = {
      id: id,
      notes: value
    };

    this.setState(newState);
  };

Will be something like: 将是这样的:

handleValueChange = event => {
    const { name, value } = event.target;
    const { id, notes } = this.state;
    this.setState(prevState => ({ id: prevState.id, notes: value}));
  };

Same in the below component: 在以下组件中相同:

handleDelete = id => {
    const newNotes = ;
    this.setState(prevState => ({ notes: R.filter(note => note.id !== id, prevState.notes) }));
  };

And so on for all the times that you update the state based on previous state value. 依此类推,您可以根据以前的状态值更新状态。

Then when you do create a list of elements in react, use key property: 然后,当您在react中创建元素列表时,使用key属性:

<SessionNoteGroup
          key={id}
          id={id}
          notes={notes}
          onDelete={this.handleDelete}
          index={i + 1}
        />

That's used by react for managing the render of list of items 反应用于管理项目列表的渲染

Try adding a key to the container div of your render 尝试将一个键添加到渲染的容器div中

return (
      <div key = {this.props.id}>
        <Grid container>
          <Grid item xs={12}>
            <TextField
              multiline
              fullWidth
              id="notes"
              name="notes"
              label="Notes"
              rows="2"
              value={notes}
              onChange={this.handleValueChange}
            />
          </Grid>
        </Grid>
        <Button variant="outlined" color="primary" onClick={this.handleDelete}>
          Delete
        </Button>
      </div>
    );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM