在实现React DnD之后发布React中的刷新子组件

我正在尝试使用React DnD在React中实现可排序列表的可排序列表。在实现事物的拖放方面之前,一切都很好。

我有一个容器组件,它呈现了这一点:

<DndProvider backend={Backend}>
                    {this.state.classifications.map((classification,index) =>
                        <Classification id={classification.id} classification={classification} reportTemplate={this} key={classification.id} index={index} />
                    )}
</DndProvider>

分类扩展了组件,其构造如下:

   constructor(props) {
        super(props);

        this.state = {
            isEditing: false,classification: props.classification
        };
    }

...,并对此进行渲染(为了简洁起见):

<div classname="panel-body">
    <DndProvider backend={Backend}>
        {this.state.classification.labels.map((label,index) =>
            <Label id={label.id} label={label} reportTemplate={this.props.reportTemplate} key={label.id} index={index} />
         )}
    </DndProvider>
</div>

依次,Label也扩展了组件,其结构如下:

 constructor(props) {
        super(props);

        this.state = {
            isEditing: false,label: props.label
        };
    }

...并进行如下渲染(为了简洁起见,也是如此):

return (
    <div classname={"panel panel-default panel-label " + (isDragging ? "dragging " : "") + (isOver ? " over" : "")}>
        <div classname="panel-heading" role="tab" id={"label-" + this.state.label.id}>
            <div classname="panel-title">
                <div classname="row">
                    <div classname="col-xs-6 label-details">
                        {this.state.isEditing
                            ? <input type="text" classname="form-control" value={this.state.label.value} onChange={e => this.props.reportTemplate.onLabelValueChange(e,this.state.label.classificationId,this.state.label.id,'value')} />
                            : <p classname="form-control-static">{this.state.label.value}</p>
                        }
                    <div classname="subuser-container">...</div>
                </div>


            </div>
        </div>
    </div>
);

所有这些都很好-当用户从Label子组件中进行更改时,它在根组件中得到更新,并且所有内容都同步并刷新。

但是,当实现React DnD时,Classification和Label组件都被包装在Drag和Drop装饰器中,以提供排序。通过拖放进行排序非常有效。 但是:这已导致元素更新停止工作(即,当对Label进行更改时,更新会正确地传递到根Component,但不会刷新下来那个树)。

分类和标签dnd的实现在render方法中都是这样的:

return connectDropTarget(connectDragSource(...));

...以及导出组件时的提示:

export default DropTarget('classification',classificationTarget,classificationDropCollect)(DragSource('classification',classificationSource,classificationDragCollect)(Classification));

有趣的是,当标签被编辑后,当用户拖放组件时,刷新就会发生。因此,就像拖放一样,它会触发组件刷新,但不会触发其他onChange函数。

这是一个很长的问题,很抱歉。我几乎可以肯定其他人也会遇到此问题,因此非常感谢任何指针。

lkj123lkj123lkj 回答:在实现React DnD之后发布React中的刷新子组件

好的,我基本上已经回答了我自己的问题,但是非常感谢那些在此处发表评论以缩小范围的人。

答案是我的状态对象复杂而又深,而React DnD的组件/装饰器实现似乎与此有关。我的假设是,装饰器的shouldComponentUpdate中有某些行为会在更新深色属性时阻止组件刷新。 React DnD自己的文档将装饰者称为“传统”,这很公平。

我更新了我们的组件,以使用挂钩而不是装饰器,它们全部变为现实。答案就是这样,如果您的DnD实现很复杂,请使用钩子。

,

这是一个没有DnD的代码示例,该示例无法正常工作,因为道具被复制到构造函数中的状态,并且在并发渲染时,道具不再被使用,仅状态被使用。

在Child中,您可以看到它会渲染,但计数器永远不会改变;在CorrectChild中,计数器将发生变化,因为它只是使用props.counter。

class Child extends React.Component {
  constructor(props) {
    super(props);
    this.state = {//copied only once in constructor
      counterFromParent: props.counter,};
  }
  rendered=0;
  render() {
    this.rendered++;
    return (
      <div>
        <h3>in broken Child rendered {this.rendered} times</h3>
        <button onClick={this.props.up}>UP</button>
        <pre>
          {JSON.stringify(this.state,undefined,2)}
        </pre>
      </div>
    );
  }
}
class CorrectChild extends React.Component {
  render() {
    //not copying props.count,just using it
    return (
      <div>
        <h3>in correct Child</h3>
        <button onClick={this.props.up}>UP</button>
        <pre>
          {JSON.stringify(this.props,2)}
        </pre>
      </div>
    );
  }
}
function App() {
  const [state,setState] = React.useState({ counter: 1 });
  const up = React.useCallback(
    () =>
      setState((state) => ({
        ...state,counter: state.counter + 1,})),[]
  );
  return (
    <div>
      <h3>state in App:</h3>
      <pre>{JSON.stringify(state,2)}</pre>
      <Child counter={state.counter} up={up} />
      <CorrectChild counter={state.counter} up={up} />
    </div>
  );
}
ReactDOM.render(<App />,document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>


<div id="root"></div>

如果您仍然在没有DnD的情况下遇到问题,则代码“有效”,那么请提供其中的Minimal,Reproducible Example“无效”。

本文链接:https://www.f2er.com/2353735.html

大家都在问