【问题标题】:React not reordering array of components on render反应不在渲染上重新排序组件数组
【发布时间】:2019-05-29 12:07:17
【问题描述】:

我正在尝试使用 react 来按顺序呈现组件列表,组件正在更新这个元素数组,但没有对它们重新排序。

伪代码;

class Form extends Component {
  //
  // .... other initialization code and logic
  //

  updatePositions() {
    //
    // re-order this.state.page.page_contents
    //
    this.setState({ page: this.state.page });
  }

  renderContents() {
    return this.state.page.page_content.map((c, i) => {
      return (<ContentItem
        key={ i }
        content={ c }
      />);
    });
  }

  render() {
    return (
      <div className="row">
        <div className="medium-12 columns">
          { this.renderContents() }
        </div>
      </div>
    );
  }
}

如果我注销 page.page_content 的结果,项目将在数组中重新排序,但是表单渲染不会以新顺序重新渲染内容

【问题讨论】:

  • 没有为这些项目设置 id。
  • 你有没有做一个可行的例子让我们看看?因为我们不知道所有内容的结构或重新排序的代码。
  • 这不是一个好方法this.setState({ page: this.state.page }) 它意味着您正在改变状态,如果您想将状态更改为先前状态的派生版本,请使用:this.setState(prevState =&gt; ....)
  • @Titus 在那个回调中我会做什么?这是我要设置新数组内容的地方吗?
  • 是的,您从回调中返回的内容将被设置为新状态,您可以这样做:this.setState(prevState =&gt; ({page: [...prevState.page].sort(.....)}))

标签: javascript reactjs jsx


【解决方案1】:

如果您的数组顺序可能会更改,则不应使用数组索引作为键。密钥应该是永久的,因为 React 使用密钥来识别组件,如果一个组件收到一个以前属于不同组件的密钥,React 认为它和以前是同一个组件。

为您的元素创建对这些元素永久有效的唯一键。

【讨论】:

    【解决方案2】:

    你可以尝试强制更新

     renderContents() {
              this.forceUpdate();           
              return this.state.page.page_content.map((c, i) => {
                  return (<ContentItem
                    key={ i }
                    content={ c }
                  />);
                });
    
              }
    

    【讨论】:

      【解决方案3】:

      不要直接改变this.state。将其带入一个新变量,然后将其添加回状态。

      永远不要直接改变 this.state,因为之后调用 setState() 可能会替换你所做的改变。将 this.state 视为不可变的。

      来自:https://reactjs.org/docs/react-component.html

      相反,您应该尝试:

        updatePositions() {
          const page_contents = [...this.state.page.page_contents]
          // re order page_contents
          this.setState({ page: { page_contents });
        }
      

      【讨论】:

        【解决方案4】:
        renderContents() {
            return this.state.page.page_content.map((c, i) => {
              return (<ContentItem
                key={ i }
                content={ c }
              />);
            });
          }
        

        这是你的代码 - key={i} i 没有改变,所以它不会重新渲染组件 - 如果你想重新渲染组件 - 请确保 - 键应该改变。

        renderContents() {
            return this.state.page.page_content.map(c => {
              return (<ContentItem
                key={ c }
                content={ c }
              />);
            });
          }
        

        c 是内容 - 如果它发生变化,那么组件将重新渲染

        this.setState({ page: this.state.page }) 这是错误的 - 你试图再次在同一个变量中设置相同的值。

        class Form extends Component {
          //
          // .... other initialization code and logic
          //
        
          updatePositions() {
            //
            // re-order this.state.page.page_contents
            //
            this.setState({ page: newValueFromAPI.page });
          }
        
          render() {
            const { page: { page_content } } = this.state
            return (
              <div className="row">
                <div className="medium-12 columns">
                  { page_content.length > 0 && (
                     page_content.map(c => <ContentItem key={c} content={c}/>)
                  )}
                </div>
              </div>
            );
          }
        }
        

        【讨论】:

        • c={ c } 不起作用,因为它为所有内容项返回 [object Object],但是 c={ JSON.stringify(c) } 确实起作用。不是一个很好的技巧,但它确实解决了问题
        • JSON.stringify(c) 将完成这项工作,但如果值没有改变,那么为什么要重新渲染它应该改变一些东西 - 如果你在对象中有一个不断变化的值然后保持作为 KEY - 它会在组件更改时重新渲染组件
        猜你喜欢
        • 2020-03-08
        • 2018-12-27
        • 2018-09-19
        • 1970-01-01
        • 2020-12-17
        • 2021-10-03
        • 1970-01-01
        • 2017-07-31
        • 1970-01-01
        相关资源
        最近更新 更多