0

我遇到了一个非常奇怪的问题,页面上只有一个组件没有被刷新,我就是不知道为什么。

这是该问题的简短视频:

https://i.gyazo.com/45e229b0867c37e48a18da7a55afb522.mp4

请注意当我单击确认时问题字符串如何变化(应该如此),但拖放窗口的卡片保持不变。它一直显示问题名称“yooo”和答案“abc,def”,而这仅对第一个问题有效。

我对 ReactJS 还是比较陌生,所以这里可能有一些我不熟悉的功能?据我所知 DragAndDrop 应该完全用下一个问题重新渲染。目前没有再次调用构造函数,它以某种方式保存了最后一个问题的数据。

此页面的渲染。DragAndDrop 在这里被调用。在 confirm() 中,currentQuestion 被设置为下一个问题。

return (
    <div>
      <h3>{currentQuestion.question}</h3>

      <DragAndDrop
        answers={currentQuestion.answers}
      />

      <Button onClick={() => confirm()}>Confirm</Button>
    </div>
  );

整个 DragAndDrop.js 对不起代码墙,它与 Beautiful-DND 的示例代码几乎相同https://codesandbox.io/s/k260nyxq9v

/* eslint-disable no-console */
/* eslint-disable react/prop-types */
import React, { Component } from "react";
import { DragDropContext, Droppable, Draggable } from "react-beautiful-dnd";

// STYLING
const grid = 8;

const getItemStyle = (isDragging, draggableStyle) => ({
  // some basic styles to make the items look a bit nicer
  userSelect: "none",
  padding: grid * 2,
  margin: `0 0 ${grid}px 0`,

  // change background colour if dragging
  background: isDragging ? "cyan" : "white",

  // styles we need to apply on draggables
  ...draggableStyle,
});

const getListStyle = (isDraggingOver) => ({
  background: isDraggingOver ? "lightblue" : "lightgrey",
  padding: grid,
  width: "100%",
});

// a little function to help us with reordering the result
const reorder = (list, startIndex, endIndex) => {
  const result = Array.from(list);
  const [removed] = result.splice(startIndex, 1);
  result.splice(endIndex, 0, removed);

  return result;
};

export default class DragAndDrop extends Component {
  constructor(props) {
    super(props);
    this.state = {
      items: props.answers,
    };
    this.onDragEnd = this.onDragEnd.bind(this);

    console.log("Answers & items");
    console.log(this.props.answers);
    console.log(this.state.items);
  }

  onDragEnd(result) {
    // dropped outside list
    if (!result.destination) {
      return;
    }

    const items = reorder(
      this.state.items,
      result.source.index,
      result.destination.index
    );

    this.setState({
      items,
    });
  }
  render() {
    return (
      <DragDropContext onDragEnd={this.onDragEnd}>
        <Droppable droppableId="droppable">
          {(provided, snapshot) => (
            <div
              {...provided.droppableProps}
              ref={provided.innerRef}
              style={getListStyle(snapshot.isDraggingOver)}
            >
              {this.state.items.map((item, index) => (
                <Draggable
                  key={item.id}
                  draggableId={item.id.toString()}
                  index={index}
                >
                  {(provided, snapshot) => (
                    <div
                      ref={provided.innerRef}
                      {...provided.draggableProps}
                      {...provided.dragHandleProps}
                      style={getItemStyle(
                        snapshot.isDragging,
                        provided.draggableProps.style
                      )}
                    >
                      {
                        item.answer +
                          " index: " +
                          index +
                          " ordering:" +
                          item.ordering /*CONTENT OF CARD*/
                      }
                    </div>
                  )}
                </Draggable>
              ))}
              {provided.placeholder}
            </div>
          )}
        </Droppable>
      </DragDropContext>
    );
  }
}
4

2 回答 2

1

我认为问题出在以下行constructor

this.state = {
  items: props.answers,
};

在构造函数中这样设置items意味着您将忽略props来自父组件的任何后续更新!如果您查看官方文档,他们会对此提出警告。

避免将道具复制到状态!这是一个常见的错误:

问题是它既是不必要的(您可以直接使用 this.props.color 代替),并且会产生错误(对 color 道具的更新不会反映在状态中)。

仅当您有意忽略道具更新时才使用此模式。在这种情况下,将 prop 重命名为 initialColor 或 defaultColor 是有意义的。然后,您可以在必要时通过更改其键来强制组件“重置”其内部状态。

如果您想依赖 的值props并相应地更改状态,您可以使用static getDerivedStateFromProps()

这是一个使用基于类的组件的工作示例,它只是使用您的组件的概念验证static getDerivedStateFromProps()(不推荐使用!)。我添加了一些虚拟数据,它们使用您在父组件中提供的相同结构,当您单击“确认”时会发生变化。此外,这是一个使用钩子的工作示例useState,它与使用和钩子做同样的事情useEffect

于 2020-09-29T08:28:32.137 回答
1

props.answers由您的父组件控制并确认功能。您的DragAndDrop组件仅在构造函数中将道具设置为初始状态。它不知道何时props更改,因为仅在您第一次propsstate构造函数中设置。您可以通过多种方式模拟道具更改,如下所示:

  1. 使用 props 更改模拟状态更改
...
constructor(props) {
    this.state = {items:props.answers}
...
}
componentDidUpdate(prevProps, PrevState) {
    if (this.props.answers && this.props.answers !== prevProps.answers) {
      this.setState({ items: this.props.answers });
    }
  }
  1. 直接使用道具,构造函数或DragAndDrop组件中的任何地方都没有状态

  2. 移动你的道具并confirm直接在你的DragAndDrop组件中

于 2020-09-29T11:32:58.400 回答