J'essaye de filtrer ma liste d'objets de tableau, puis j'essaie de l'afficher dans ListView avec le nouveau DataSource. Cependant, la liste n'est pas filtrée. Je sais que ma fonction de filtre fonctionne correctement. (Je l'ai vérifié dans le fichier console.log)
J'utilise Redux pour mapper mon état pour soutenir. Et puis en essayant de filtrer l'accessoire. Est-ce la mauvaise façon?
Voici mon 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);
Qu'est-ce que je fais mal ici?
C'est un peu difficile de suivre ce qui se passe ici. Je voudrais simplifier pour être comme suit:
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);
Quelques points:
assetFetch
, vous devriez donc probablement le renvoyer dans componentDidMount
.componentWillMount
à componentDidMount
. Il est recommandé de mettre l'extraction asynchrone componentDidMount
. Cela peut être important si vous effectuez un rendu côté serveur.Une chose qui me préoccupe un peu est le mode de récupération dans un composant, de le placer dans un état global, puis de compter sur ce composant pour réagir au changement d'état global. Ainsi, le changement d'état global devient un effet secondaire du simple fait de regarder quelque chose. Je suppose que vous le faites parce que assets
est utilisé ailleurs et qu’il est pratique de les actualiser depuis le serveur afin qu’ils apparaissent dans d’autres composants qui ne les récupèrent pas. Ce modèle peut entraîner des bogues difficiles à trouver.
Vous devez faire setState
pour déclencher le rendu. Voici comment je le ferais -
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)}
.....
/>
}