React Native - 强制ListView在数据未更改时重新呈现

时间:2016-06-23 19:54:43

标签: listview reactjs react-native

是否可以强制ListView重新渲染,即使dataSource中的数据没有改变?我在我的应用程序的标签栏中有一个ListView,我希望每次选择该标签时都重绘它,无论数据是相同还是已经更改。

this.state = {
  data: props.data,
  dataSource: new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2})
}

componentWillMount() {
  this.setState({
    dataSource: this.state.dataSource.cloneWithRows(nextProps.data)
  })
}

render() {
  <ListView
   dataSource={this.state.data}
   renderRow={this._renderRow}
  />
}

我尝试使用rowHasChanged参数,但这没有帮助。任何帮助将不胜感激

5 个答案:

答案 0 :(得分:32)

因此,根据我的理解,您的用例是因为value更改而重新呈现ListView的所有行。我不知道value是什么,由你决定,但我会用value来解释我的答案:

有几种方法可以解决这个问题。各有利弊:

  • 简单方法:只是<ListView key={value} ... /> !!它告诉React ListView需要在值更改时重新呈现(它将被卸载,重新安装)。
  • &#34; hacky way&#34;。替换为新的DataSource。 this.setState({ dataSource: new ListView.DataSource({ rowHasChanged: (r1, r2) => r1 !== r2 }).cloneWithData(this.props.data) });
  • (imo)最佳实践方式:在数据中,合并value并正确实现rowHasChanged。例如:(r1, r2) => r1.value !== r2.value && r1.data !== r2.data(&lt; - 这只是表示数据的一种可能方式,你必须选择你的格式,我只是假设你用nextProps.data.map(data => ({ data, value })克隆了dataSource。)

对我来说,第三个也是最后一个解决方案是最好的,因为:

  • 它可以很好地扩展到更多重新渲染的条件(其他value s)
  • 可能会发生只有部分行实际应该重新渲染的情况,在这种情况下,您不应该重新渲染所有行以获得更好的性能。

这是我就该主题提出的另一个答案:

What are the exact inputs to rowHasChanged in ListView.DataSource

答案 1 :(得分:2)

使用不变性方法

“更新”这个的最好方法是克隆有问题的数据项,而不是像arr[i] = { ...arr[i], someKey: newValue } 已经暗示的那样进行标记黑客攻击。而不是更新单个项目,通过克隆来更改“指针”本身。

对于此特定问题,请更新数组中的项目。

{{1}}

这将用“newValue”替换“someKey”属性,当前行将有一个新指针。

这是一个很好的资源,可以了解现代JavaScript中对于本机用途的不可变性:https://wecodetheweb.com/2016/02/12/immutable-javascript-using-es6-and-beyond/

答案 2 :(得分:0)

您可以调用this.forceUpdate()强制重新渲染。

您可以在附加到选项卡的简单onClick处理程序中执行此操作。

更多信息here, on the official docs

但是,如果还有其他规则规定是否应该有更新,您可以尝试将dataSource替换为新的,使其具有新的引用。这也将使其更新。

的内容

this.setState({ data : newDataSource… });

答案 3 :(得分:0)

这可能有点矫枉过正,但我​​只是替换了componentDidUpdate上的数据源(也许这对性能有害?我不知道哈哈)

  componentWillMount() {
   this.ds = new ListView.DataSource({
     rowHasChanged: (r1, r2) => r1 !== r2,
    });
   this.dataSource = this.ds.cloneWithRows(this.props.shiftsList);
  }

componentDidUpdate() {
  this.ds = new ListView.DataSource({
   rowHasChanged: (r1, r2) => r1 !== r2,
  });
 this.dataSource = this.ds.cloneWithRows(this.props.shiftsList);
}

答案 4 :(得分:0)

我知道我有点晚了,但我确信这仍然有用。对此有一个更简单的方法......杰森提供的第一个例子无论如何都是一个很好的解决方案,但我想的是那些容易混淆的人。如果是这样,请使用此功能。

// On component initalization
componentWillMount() {
    this.UpdateData();
}

// When the component updates
componentDidUpdate() {
    if (this.state.data != this.props.data)
        this.UpdateData();
}

// Function to update the ListView component data
UpdateData() {
    var source = new ListView.DataSource({
        rowHasChanged: (r1, r2) => r1 !== r2
    });

    this.setState({
        data: this.props.data,
        dataSource: source.cloneWithRows(this.props.data)
    });
}

我还建议在您的应用程序中实现Redux。这样,您可以将新的,更新的数组值存储在reducer中,然后将其存储在本地状态,然后在componentDidUpdate函数中使用if语句来确定数据是否已更新。

React调试器不记录任何基于性能的投诉或警告......