【问题标题】:Button removes list items and changes their ordning | React按钮删除列表项并更改它们的排序 |反应
【发布时间】:2018-03-06 09:04:07
【问题描述】:

我有一个按钮,当按下它时应该可以切换列表中的更多项目。我在构造函数中设置了默认状态:

constructor(props) {
  super(props)
  this.state = {
    showCount: 10,
    expanded: false
  }
}

因此列表中的默认项目数将为 10,并且不会扩展。然后我创建了一个应该改变状态并加载更多列表项的函数:

loadMore() {
  const { showCount } = this.state
  const { events } = this.props
  showCount === 10
    ? this.setState({ showCount: events.reverse().length, expanded: true })
    : this.setState({ showCount: 10, expanded: false })
}

并创建了一个“按钮”,如果expanded 状态为真或假,它应该更改其文本:

const toggleMore = (
  <div className="text-center">
    <a className="show-more" onClick={() => this.loadMore()}>
      {this.state.expanded ? (
        <span>Visa mindre</span>
      ) : (
        <span>Visa mer</span>
      )}
    </a>
  </div>
)

然后是使用.sliceshowCount 变量的列表项组件:

const mappedEvents =
  events.length === 0 ? (
    <p style={{ textAlign: 'center' }}>No events</p>
  ) : (
    events
      .reverse()
      .slice(0, this.state.showCount)
      .map((event, i) => {
        return (
          <div>
            <EventItem
              key={i}
              ...
            />
          </div>
        )
      })
  )

我的问题

所以这个按钮在我第一次使用时效果很好。如果我来到我的页面,我可以看到所有 10 个列表项,并且当按下按钮时,文本会发生变化。 但是当我第二次按下它时(expanded: true)我的所有列表项消失。当我第三次按下它时,我的列表项的顺序发生了变化,这意味着.revers() 显然不再起作用了。当我第四次按下它时,它又回到了第一阶段; 10 个清单项目和排序是应该的。在那之后它只是不断重复。

所以我只想知道我在这里做错了什么以及为什么按钮会这样。

感谢阅读!

【问题讨论】:

  • 试试onClick={this.loadMore.bind(this)}
  • @ChrisG 感谢您的回复。没有运气尝试过:(
  • 嗨,有几个问题:1)你能解释一下,你为什么要使用反向?我无法通过查看提供的代码来掌握它。 2) 你在哪里定义 toggleMore 和 mappedEvents 常量?
  • 我构建了这个codesandbox.io/s/zxmjkr4l3x 似乎工作正常。
  • @GlebKost 是的,我正在使用 reverse() 因为我需要从我的 API 中获取最新的列表项。我在我的 render() 中定义了这两个常量。

标签: javascript reactjs


【解决方案1】:

基本问题是 events.reverse() 是破坏性的,它实际上变异原始数组,它不简单地返回一个新的反转数组。这个数组来自 props,这也是一个问题——你绝对不应该修改来自 props 的东西,你不知道父组件以后是否会用新数组覆盖它。

此外,如果您在渲染期间使用 reverse(),请记住,渲染可能运行的次数可能比您意识到的要多。每次渲染它都会再次反转数组。

我在这里的建议是仅在渲染期间执行数组转换,并以非破坏性的方式进行操作。获得一个新的反转数组的一种方法是先用 slice 制作一个副本,然后 然后 反转它,如下所示:

const reversed = events.slice().reverse();

另外我注意到你正在使用events.reverse().length——大概这与 events.length 相同,你需要在这里改变数组吗?

【讨论】:

  • 我注意到的是,当我在 events.reverse().length 删除 reverse() 时,它不会在我第三次按下按钮时删除列表项,但是当按下按钮展开所有内容时,列表是不再反转,直到我再次按下它。
  • 我解释了这一点,每次渲染时,您都会再次反转数组。如果没有看到完整的组件代码,我真的无法再调试了,我不确定这些 sn-ps 是如何相互交互的。
  • 我明白了。我创建了一个要点:gist.github.com/Martinnord/2ccf20edf72af2c4ffb23d4ea9846192 感谢您抽出宝贵时间!
  • 看着这个我仍然不完全确定为什么列表消失
  • 但是 .reverse() 是一个大问题。你理解“Array.reverse() 是破坏性操作”这句话吗?
【解决方案2】:

我会删除倒车部分,我不确定你最终是否需要它。并将这些 const 提取到单独的方法甚至单独的小组件中。

代码如下:

import React, { Component } from 'react';
import { render } from 'react-dom';

class App extends Component {
  render() {
    return (
      <List events={[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15]} />
    );
  }
}

class List extends Component {
  constructor(props) {
    super(props)
    this.state = {
      showCount: 10,
      expanded: false
    }
    this.renderMappedEvents = this.renderMappedEvents.bind(this);
    this.renderToggleMoreBtn = this.renderToggleMoreBtn.bind(this);
  }

  loadMore() {
    const { showCount } = this.state
    const { events } = this.props
    showCount === 10
      ? this.setState({ showCount: events.length, expanded: true })
      : this.setState({ showCount: 10, expanded: false })
  }

  renderMappedEvents() {
    const { events } = this.props; 
    return events.length === 0 ? (
    <p style={{ textAlign: 'center' }}>No events</p>
    ) : (
      events
        .slice(0, this.state.showCount)
        .map((event, i) => {
          return (
            <div>
              { event }
            </div>
          )
        })
    )
  }

  renderToggleMoreBtn() {
    return (
      <div className="text-center">
        <a className="show-more" onClick={() => this.loadMore()}>
          {this.state.expanded ? (
            <span>Visa mindre</span>
          ) : (
            <span>Visa mer</span>
          )}
        </a>
      </div>
    );
  }

  render() {
    return (
      <div>{[
        this.renderMappedEvents(),
        this.renderToggleMoreBtn()
      ]}</div>);
  }

}

render(<App />, document.getElementById('root'));

还有一个工作 sn-p 的链接: https://stackblitz.com/edit/react-kmdz9f

【讨论】:

  • 顺便说一句,如果你能提供你不工作的解决方案作为一个工作的 sn-p,我就能准确地指出它被破坏的地方。
  • 好的,现在我想我得到了反转要求,因为您需要从某个地方获得的数组中的最新事件。我会第二次@Peter Hurst,最好在某个地方做一次events.slice().reverse();,而不是每次渲染。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-12
  • 2023-01-20
  • 2017-10-09
  • 2023-01-12
相关资源
最近更新 更多