简体   繁体   English

如何在ListView React-native中过滤数据?

[英]How to filter data in ListView React-native?

I am trying to filter my array object list and then trying to display in the ListView with new DataSource. 我试图过滤我的数组对象列表,然后尝试使用新的DataSource在ListView中显示。 However, the list is not getting filtered. 但是,列表未被过滤。 I know that my filter function works correctly. 我知道我的过滤功能正常工作。 ( I checked it in the console.log ) (我在console.log中查了一下)

I am using Redux to map my state to prop. 我正在使用Redux将我的状态映射到prop。 And then trying to filter the prop. 然后尝试过滤道具。 Is this the wrong way? 这是错误的方式吗?

Here is my code: 这是我的代码:

/*global fetch:false*/
import _ from 'lodash';
import React, { Component } from 'react';
import { ListView, Text as NText } from 'react-native';
import { connect } from 'react-redux';
import { Actions } from 'react-native-router-flux';
import {
  Container, Header, Item,
  Icon, Input, ListItem, Text,
  Left, Right, Body, Button
} from 'native-base';


import Spinner from '../common/Spinner';
import HealthImage from '../misc/HealthImage';
import { assetsFetch } from '../../actions';

const ds = new ListView.DataSource({
  rowHasChanged: (r1, r2) => r1 !== r2
});

class AssetsList extends Component {
  componentWillMount() {
    this.props.assetsFetch();

    // Implementing the datasource for the list View
    this.createDataSource(this.props.assets);
  }

  componentWillReceiveProps(nextProps) {
    // Next props is the next set of props that this component will be rendered with.
    // this.props is still equal to the old set of props.
    this.createDataSource(nextProps.assets);
  }

  onSearchChange(text) {
    const filteredAssets = this.props.assets.filter(
      (asset) => {
        return asset.name.indexOf(text) !== -1;
      }
    );

    this.dataSource = ds.cloneWithRows(_.values(filteredAssets));
  }

  createDataSource(assets) {
    this.dataSource = ds.cloneWithRows(assets);
  }


  renderRow(asset) {
    return (
      <ListItem thumbnail>
          <Left>
              <HealthImage health={asset.health} />
          </Left>
          <Body>
              <Text>{asset.name}</Text>

              <NText style={styles.nText}>
                Location: {asset.location} |
                Serial: {asset.serial_number}
              </NText>
              <NText>
                Total Samples: {asset.total_samples}
              </NText>

          </Body>
          <Right>
              <Button transparent onPress={() => Actions.assetShow()}>
                  <Text>View</Text>
              </Button>
          </Right>
      </ListItem>
    );
  }



  render() {
    return (
     <Input
                  placeholder="Search"
                  onChangeText={this.onSearchChange.bind(this)}
                />
        <ListView
          enableEmptySections
          dataSource={this.dataSource}
          renderRow={this.renderRow}
        />


    );
  }
}

const mapStateToProps = state => {
  return {
    assets: _.values(state.assets.asset),
    spinner: state.assets.asset_spinner
  };
};

export default connect(mapStateToProps, { assetsFetch })(AssetsList);

What am I doing wrong here? 我在这做错了什么?

It's a little hard to follow what's going on here. 跟踪这里发生的事情有点困难。 I would simplify it to be like so: 我会简化它是这样的:

class AssetsList extends Component {
  state = {};

  componentDidMount() {
    return this.props.assetsFetch();
  }

  onSearchChange(text) {
    this.setState({
      searchTerm: text
    });
  }

  renderRow(asset) {
    return (
      <ListItem thumbnail>
          <Left>
              <HealthImage health={asset.health} />
          </Left>
          <Body>
              <Text>{asset.name}</Text>

              <NText style={styles.nText}>
                Location: {asset.location} |
                Serial: {asset.serial_number}
              </NText>
              <NText>
                Total Samples: {asset.total_samples}
              </NText>

          </Body>
          <Right>
              <Button transparent onPress={() => Actions.assetShow()}>
                  <Text>View</Text>
              </Button>
          </Right>
      </ListItem>
    );
  }

  getFilteredAssets() {

  }

  render() {
    const filteredAssets = this.state.searchTerm
      ? this.props.assets.filter(asset => {
          return asset.name.indexOf(this.state.searchTerm) > -1;
        })
      : this.props.assets;
    const dataSource = ds.cloneWithRows(filteredAssets);
    return (
     <Input
                  placeholder="Search"
                  onChangeText={this.onSearchChange.bind(this)}
                />
        <ListView
          enableEmptySections
          dataSource={dataSource}
          renderRow={this.renderRow}
        />
    );
  }
}

const mapStateToProps = state => {
  return {
    assets: _.values(state.assets.asset),
    spinner: state.assets.asset_spinner
  };
};

export default connect(mapStateToProps, { assetsFetch })(AssetsList);

A few points: 几点:

  1. Your component is stateful. 您的组件是有状态的。 There is one piece of state that belongs only to the component: the search term. 有一个状态只属于组件:搜索术语。 Keep that in component state. 保持组件状态。
  2. Don't change the data source in life cycle functions. 请勿更改生命周期功能中的数据源。 Do it the latest point you know it's needed: in render. 这是你知道它需要的最新点:渲染。
  3. I'm guessing that there's something async in assetFetch , so you probably should return it in componentDidMount . 我猜测assetFetch中有异步,所以你可能应该在componentDidMount返回它。
  4. I changed from componentWillMount to componentDidMount . 我从componentWillMount更改为componentDidMount It's recommended to put async fetching componentDidMount . 建议使用异步提取componentDidMount This can matter if you ever do server side rendering. 如果您进行服务器端渲染,这可能很重要。
  5. Skip filtering if there is no search term. 如果没有搜索词,则跳过过滤。 This would only matter if the list is very large. 只有列表非常大,这才有意义。

One thing I have a little concern with is the pattern of fetching inside a component, putting it in global state, and then relying on that component to react to the global state change. 我有点担心的一件事是在组件内部获取模式,将其置于全局状态,然后依靠该组件来响应全局状态变化。 Thus changing global state becomes a side effect of simply viewing something. 因此,改变全球状态成为简单地观察某事物的副作用。 I assume you are doing it because assets is used elsewhere, and this is a convenient point to freshen them from the server so that they will show up in other components that do not fetch them. 我假设您正在这样做,因为assets在其他地方使用,这是一个方便的点,从服务器刷新它们,以便它们将显示在其他不提取它们的组件中。 This pattern can result in hard-to-find bugs. 这种模式可能导致难以发现的错误。

You need to do setState to trigger render. 您需要执行setState来触发渲染。 Here's how I would do it - 这是我将如何做到的 -

constructor(props) {
  super(props);
  this.ds = new ListView.DataSource({ rowHasChanged: (r1,r2) => r1 !== r2 });
  this.state = {
    assets: []
  };
}

componentWillMount() {
  this.props.assetsFetch();
  this.setState({
    assets: this.props.assets
  });
}

componentWillReceiveProps(nextProps) {
  this.setState({
    assets: nextProps.assets
  });
}

onSearchChange(text) {
  const filteredAssets = this.props.assets.filter(asset => asset.name.indexOf(text) !== -1);
  this.setState({
    assets: _.values(filteredAssets)
  });
}


render() {
  ...
  <ListView
    dataSource={this.ds.cloneWithRows(this.state.assets)}
    .....
  />
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM