写作时间:20年末或21年初吧具体时间记不得了
React-Native版本:0.63.2
目标平台:Android、iOS
FlatList是RN中的一个重要组件,打算做一个系列,对其使用方法和注意事项进行系统的学习整理,这期主要是记录keyExtractor的若干使用场景和对应现象
父组件维护一组复杂的列表数据,其中keyExtractor取列表中每一项的key值,当点击按钮之后,数据更新。
代码如下:
//App.js
import React from 'react';
import {View, Button, FlatList} from 'react-native';
import Item from './Item';
export default class App extends React.Component {
constructor() {
super();
this.state = {
list: [
{key: '1', data: {name: 'aaa', age: 11}},
{key: '2', data: {name: 'bbb', age: 22}},
{key: '3', data: {name: 'ccc', age: 33}},
{key: '4', data: {name: 'ddd', age: 44}},
{key: '5', data: {name: 'eee', age: 55}},
],
};
this.temp = [
{key: '6', data: {name: 'fff', age: 66}},
{key: '7', data: {name: 'ggg', age: 77}},
{key: '8', data: {name: 'hhh', age: 88}},
];
}
render() {
console.log('App_render()');
return (
<View>
{this.renderButton()}
{this.renderList()}
</View>
);
}
renderButton = () => {
console.log('App_renderButton()');
return <Button title={'RefreshData'} onPress={this.onButtonPress} />;
};
renderList = () => {
console.log('App_renderList()');
return (
<FlatList
data={this.state.list}
renderItem={this.renderItem}
keyExtractor={this.keyExtractor}
/>
);
};
renderItem = ({item}) => {
return <Item itemData={item} />;
};
onButtonPress = () => {
this.setState({list: this.temp});
};
keyExtractor = (item) => {
return item.key;
};
}
//Item.js
import React from 'react';
import {Text} from 'react-native';
export default class Item extends React.Component {
constructor(props) {
super(props);
console.log('Item_constructor()', 'key:', this.props.itemData.key);
}
render() {
console.log('Item_render()', 'key:', this.props.itemData.key);
return <Text>{this.props.itemData.data.name}</Text>;
}
}
控制台日志如下:
LOG App_render()
LOG App_renderList()
LOG App_renderButton()
LOG Item_constructor() key: 1
LOG Item_render() key: 1
LOG Item_constructor() key: 2
LOG Item_render() key: 2
LOG Item_constructor() key: 3
LOG Item_render() key: 3
LOG Item_constructor() key: 4
LOG Item_render() key: 4
LOG Item_constructor() key: 5
LOG Item_render() key: 5
->点击按钮触发数据更新,界面重新渲染
LOG App_render()
LOG App_renderList()
LOG App_renderButton()
LOG Item_constructor() key: 6
LOG Item_render() key: 6
LOG Item_constructor() key: 7
LOG Item_render() key: 7
LOG Item_constructor() key: 8
LOG Item_render() key: 8
小结:若数据变化且列表中的key值与原数据不同,则子组件会触发构造函数,也就是说,会产生新的子组件
与情景1类似,但keyExtractor设置为列表数据中的name,再观察结果
代码的修改如下:
//App.js
keyExtractor = (item) => {
return item.data.name;
};
控制台日志如下:
LOG App_render()
LOG App_renderList()
LOG App_renderButton()
LOG Item_constructor() key: 1
LOG Item_render() key: 1
LOG Item_constructor() key: 2
LOG Item_render() key: 2
LOG Item_constructor() key: 3
LOG Item_render() key: 3
LOG Item_constructor() key: 4
LOG Item_render() key: 4
LOG Item_constructor() key: 5
LOG Item_render() key: 5
->点击按钮触发数据更新,界面重新渲染
LOG App_render()
LOG App_renderList()
LOG App_renderButton()
LOG Item_constructor() key: 6
LOG Item_render() key: 6
LOG Item_constructor() key: 7
LOG Item_render() key: 7
LOG Item_constructor() key: 8
LOG Item_render() key: 8
小结:可以看出keyExtractor无论是设置成数据中的key还是data.name,只要是新的数据中keyExtractor所对应的数据发生了改变,就必然会触发构造函数,创建新的子组件。或者说子组件的创建与keyExtractor绑定的数据层级无关。
当数据更新时,如果新的数据的keyExtractor所对应的值无新内容,子组件的情况?
以情景1作为基础,keyExtractor对应列表数据中的key值,修改用于更新的数据this.temp,修改内容如下:
//App.js
this.temp = [
{key: '1', data: {name: 'fff', age: 66}},
{key: '2', data: {name: 'ggg', age: 77}},
{key: '3', data: {name: 'hhh', age: 88}},
];
可以看出,key值没有新的内容,但是内部data数据已经完全修改,最终控制台的日志如下:
LOG App_render()
LOG App_renderList()
LOG App_renderButton()
LOG Item_constructor() key: 1
LOG Item_render() key: 1
LOG Item_constructor() key: 2
LOG Item_render() key: 2
LOG Item_constructor() key: 3
LOG Item_render() key: 3
LOG Item_constructor() key: 4
LOG Item_render() key: 4
LOG Item_constructor() key: 5
LOG Item_render() key: 5
->点击按钮触发数据更新,界面重新渲染
LOG App_render()
LOG App_renderList()
LOG App_renderButton()
LOG Item_render() key: 1
LOG Item_render() key: 2
LOG Item_render() key: 3
通过上面的日志可以看出,不再有新的子组件生成
基于情景3,如果新数据中有部分数据含有新的key值
需要替换的代码如下:
//App.js
this.temp = [
{key: '1', data: {name: 'fff', age: 66}},
{key: '6', data: {name: 'ggg', age: 77}},
{key: '7', data: {name: 'hhh', age: 88}},
];
日志如下:
LOG App_render()
LOG App_renderList()
LOG App_renderButton()
LOG Item_constructor() key: 1
LOG Item_render() key: 1
LOG Item_constructor() key: 2
LOG Item_render() key: 2
LOG Item_constructor() key: 3
LOG Item_render() key: 3
LOG Item_constructor() key: 4
LOG Item_render() key: 4
LOG Item_constructor() key: 5
LOG Item_render() key: 5
->点击按钮触发数据更新,界面重新渲染
LOG App_render()
LOG App_renderList()
LOG App_renderButton()
LOG Item_render() key: 1
LOG Item_constructor() key: 6
LOG Item_render() key: 6
LOG Item_constructor() key: 7
LOG Item_render() key: 7
由日志可以看出,keyExtractor决定了子组件是否需要新建。只要有新的keyExtractor,那么就会构造新的子组件