新しいFlatListコンポーネントに問題があります。具体的には、行が変更に依存していることを支持している場合でも、行を再レンダリングしません。
FlatListのドキュメントには次のように書かれています:
これはPureComponentです。つまり、小道具が浅いままの場合は再レンダリングされません。 renderItem関数が依存するすべてのものが、更新後===ではないpropとして渡されることを確認してください。そうでない場合、UIは変更時に更新されない可能性があります。これには、データプロパティと親コンポーネントの状態が含まれます。
質問
ただし、selectedCategoryアイテムのIDを変更すると(行が「選択」されているかどうかを示す小道具)、小道具を再レンダリングする必要があると考えています。私は間違っていますか?
リストコンポーネントと行コンポーネントの両方の「componentWillReceiveProps」メソッドをチェックすると、リストは更新を正常に受け取りますが、行のライフサイクルメソッドは呼び出されません。
リストコンポーネントにランダムで役に立たないブール状態値を含め、小道具が更新されたときに前後に切り替えると、動作しますが、なぜかわかりませんか?
state = { updated: false };
componentWillReceiveProps(nextProps) {
this.setState(oldstate => ({
updated: !oldstate.updated,
}));
}
<FlatList
data={this.props.items.allAnimalCategories.edges}
renderItem={this._renderRow}
horizontal={true}
keyExtractor={(item, index) => item.node.id}
randomUpdateProp={this.state.updated}
/>
コード
コードの構造は次のとおりです。すべてのロジックと状態を含むコンテナコンポーネントがあります。これには、FlatListコンポーネント(プレゼンテーション、状態なし)が含まれ、これにはカスタムプレゼンテーション行が含まれます。
Container
Custom list component that includes the FlatList component
(presentational, stateless) and the renderRow method
Custom row (presentational, stateless)
コンテナには次のコンポーネントが含まれます。
<CustomList
items={this.props.viewer}
onCategoryChosen={this._onCategoryChosen}
selectedCategory={this.state.report.selectedCategory}
/>
CustomList:
class CustomList extends Component {
_renderRow = ({ item }) => {
return (
<CustomListRow
item={item.node}
selectedCategory={this.props.selectedCategory}
onPressItem={this.props.onCategoryChosen}
/>
);
};
render() {
return (
<View style={_styles.container}>
<FlatList
data={this.props.items.categories.edges}
renderItem={this._renderRow}
horizontal={true}
keyExtractor={(item, index) => item.node.id}
randomUpdateProp={this.state.updated}
/>
</View>
);
}
}
(データはリレーから取得されます)
最後に行:
render() {
const idsMatch = this.props.selectedCategory.id == this.props.item.id;
return (
<TouchableHighlight onPress={this._onItemPressed}>
<View style={_styles.root}>
<View style={[
_styles.container,
{ backgroundColor: this._getBackgroundColor() },
]}>
{idsMatch &&
<Image
style={_styles.icon}
source={require('./../../res/img/asd.png')}
/>}
{!idsMatch &&
<Image
style={_styles.icon}
source={require('./../../res/img/dsa.png')}
/>}
<Text style={_styles.text}>
{capitalizeFirstLetter(this.props.item.name)}
</Text>
</View>
<View style={_styles.bottomView}>
<View style={_styles.greyLine} />
</View>
</View>
</TouchableHighlight>
);
}
この行はそれほど興味深いものではありませんが、完全にステートレスであり、その親の小道具に依存していることを示すために含めました。
状態は次のように更新されます。
_onCategoryChosen = category => {
var oldReportCopy = this.state.report;
oldReportCopy.selectedCategory = category;
this.setState(Object.assign({}, this.state, { report: oldReportCopy }));
};
状態は次のようになります。
state = {
...
report: defaultStateReport,
};
const defaultStateReport = {
selectedCategory: {
id: 'some-long-od',
name: '',
},
...
};
ここでの問題は、
_onCategoryChosen = category => {
var oldReportCopy = this.state.report; // This does not create a copy!
oldReportCopy.selectedCategory = category;
this.setState(Object.assign({}, this.state, { report: oldReportCopy }));
};
これは
_onCategoryChosen = category => {
var oldReportCopy = Object.assign({}, this.state.report);
oldReportCopy.selectedCategory = category;
// setState handles partial updates just fine, no need to create a copy
this.setState({ report: oldReportCopy });
};
FlatListの小道具は同じままです。_renderRow
関数は、変更するselectedCategory
小道具に依存する場合があります(最初の間違いでない場合)が、FlatListコンポーネントはそれを認識しません。これを解決するには、 extraData
propを使用します。
<FlatList
data={this.props.items.categories.edges}
renderItem={this._renderRow}
horizontal={true}
keyExtractor={(item, index) => item.node.id}
extraData={this.props.selectedCategory}
/>
props to extraData in flat listコンポーネントをこのように渡すだけで、この問題を解決できます。
<FlatList
data={this.props.data}
extraData={this.props}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
ニメリアンに同意します。また、状態が配列の場合、次の操作を行うことで状態から配列オブジェクトを作成できます。
var oldReportCopy = Object.assign([], this.state.report);
次に、.Push()メソッドを使用して、次のように新しいオブジェクトを追加します。
oldReportCopy.Push(selectedCategory);
その後、この新しい配列オブジェクトを状態に戻すことができます。
this.setState({ report: oldReportCopy });
他の人には当てはまらないかもしれませんが、FlatListによってレンダリングされているアイテムの配列が空になったときだけ問題が発生していることに気付きました。私の場合は、FlatListをまったくレンダリングせず、代わりに別のビューをレンダリングする必要がありました。当然、「再レンダリングしない」という問題が修正されました。