如何在 React Native 中使用 FlatList 和 MobX
如何在 React Native 中使用 FlatList 和 MobX
介绍
在开发 React Native 应用时,我们经常需要使用列表来展示数据。React Native 提供了一个高性能的滚动列表组件,叫做 FlatList,它可以展示大量的数据,并且只渲染当前可见的项目。
但是,如何管理和更新列表中的数据呢?这时候,我们就需要一个状态管理库来帮助我们。MobX 是一个简单、可扩展和强大的状态管理库,它可以让我们用最少的代码来管理和更新我们的应用状态,并且自动优化渲染效果。
在本文中,我们将介绍如何在 React Native 中使用 FlatList 和 MobX 来显示一个待办事项列表。我们将使用 MobX 的 observable 来存储和修改数据,使用 observer 来让组件响应数据的变化,以及使用一些技巧来解决一些常见的问题。
创建待办事项类和列表类
首先,我们需要创建一个待办事项的类,用来表示每个待办事项的数据结构。我们需要给每个待办事项一个 id,一个 title 和一个 done 属性,分别表示唯一标识、标题和完成状态。我们还需要给这个类一个 toggle 方法,用来切换完成状态。
为了让这个类变成 observable,也就是可以被 MobX 跟踪和响应的状态或值,我们需要使用 makeAutoObservable 这个函数来包装它。这个函数会自动把类中的属性和方法变成 observable 和 action。
import { makeAutoObservable } from "mobx";
// 创建一个待办事项的类
class Todo {
id = Math.random();
title = "";
done = false;
constructor(title) {
makeAutoObservable(this);
this.title = title;
}
toggle() {
this.done = !this.done;
}
}
接下来,我们需要创建一个待办事项列表的类,用来表示整个列表的数据结构。我们需要给这个类一个 todos 属性,用来存储所有的待办事项。我们还需要给这个类两个方法,分别是 add 和 remove,用来添加和删除待办事项。
同样地,为了让这个类变成 observable,我们也需要使用 makeAutoObservable 这个函数来包装它。
import { makeAutoObservable } from "mobx";
// 创建一个待办事项列表的类
class TodoList {
todos = [];
constructor() {
makeAutoObservable(this);
}
add(todo) {
this.todos.push(new Todo(todo));
}
remove(todo) {
this.todos = this.todos.filter((t) => t.id !== todo.id);
}
}
最后,我们需要创建一个待办事项列表的实例,用来作为我们应用的状态源。
import { makeAutoObservable } from "mobx";
// 创建一个待办事项列表的实例
const todoList = new TodoList();
创建输入组件
接下来,我们需要创建一个用于输入待办事项的组件。这个组件需要有一个文本输入框和一个按钮,用来输入标题和添加待办事项。
为了让这个组件能够响应数据的变化,我们需要使用 observer 这个函数来包装它。这个函数会把组件变成 reaction,也就是当 observable 发生变化时自动执行的副作用或计算。
在这个组件中,我们使用 React 的 useState 钩子来存储文本输入框的值,并且使用 onChangeText 属性来更新它。当用户点击按钮时,我们调用 todoList 的 add 方法来添加一个新的待办事项,并且清空文本输入框。
import React from "react";
import { View, Text, TextInput, Button } from "react-native";
import { observer } from "mobx-react";
// 创建一个用于输入待办事项的组件
const TodoInput = observer(() => {
const [text, setText] = React.useState("");
const handleAdd = () => {
if (text.trim()) {
todoList.add(text);
setText("");
}
};
return (
<View style={{ flexDirection: "row", margin: 10 }}>
<TextInput
style={{ flex: 1, borderWidth: 1, borderColor: "gray", padding: 10 }}
value={text}
onChangeText={setText}
placeholder="Enter a todo"
/>
<Button title="Add" onPress={handleAdd} />
</View>
);
});
创建列表组件
接下来,我们需要创建一个用于显示待办事项列表的组件。这个组件需要使用 FlatList 来展示数据,并且提供一些操作按钮,用来切换完成状态和删除待办事项。
同样地,为了让这个组件能够响应数据的变化,我们也需要使用 observer 这个函数来包装它。
在这个组件中,我们使用 FlatList 的 data 属性来传入 todoList 的 todos 属性,用来表示列表的数据源。我们还需要使用 keyExtractor 属性来指定每个项目的唯一标识,以及使用 renderItem 属性来指定每个项目的渲染方式。
但是,这里有一个问题。由于 MobX 的数组是对象,而 FlatList 的 data 属性期望一个数组,所以我们不能直接传入 todoList.todos。我们需要用 toJS 或者 slice 来转换一下,或者用扩展运算符(…)来创建一个新的数组。这样才能让 FlatList 正常工作。
import React from "react";
import { View, Text, Button, FlatList } from "react-native";
import { observer } from "mobx-react";
// 创建一个用于显示待办事项列表的组件
const TodoList = observer(() => {
return (
<FlatList
data={todoList.todos.slice()}
keyExtractor={(item) => item.id.toString()}
renderItem={({ item }) => <TodoItem todo={item} />}
/>
);
});
创建项目组件
接下来,我们需要创建一个用于显示单个待办事项的组件。这个组件需要显示标题和完成状态,并且提供两个按钮,用来切换完成状态和删除待办事项。
同样地,为了让这个组件能够响应数据的变化,我们也需要使用 observer 这个函数来包装它。
在这个组件中,我们使用 Text 组件来显示标题,并且根据 done 属性来决定是否添加删除线。我们还使用 Button 组件来提供两个操作按钮,并且调用 todo 的 toggle 方法和 todoList 的 remove 方法来执行相应的操作。
import React from "react";
import { View, Text, Button } from "react-native";
import { observer } from "mobx-react";
// 创建一个用于显示单个待办事项的组件
const TodoItem = observer(({ todo }) => {
return (
<View style={{ flexDirection: "row", alignItems: "center", margin: 10 }}>
<Text
style={{
flex: 1,
textDecorationLine: todo.done ? "line-through" : "none",
}}
>
{todo.title}
</Text>
<Button title={todo.done ? "Undo" : "Done"} onPress={() => todo.toggle()} />
<Button title="Remove" onPress={() => todoList.remove(todo)} />
</View>
);
});
创建根组件
最后,我们需要创建一个根组件,用来包含输入和列表组件,并且导出为默认模块。
import React from "react";
import { View } from "react-native";
// 创建一个根组件,包含输入和列表组件
const App = () => {
return (
<View style={{ flex: 1 }}>
<TodoInput />
<TodoList />
</View>
);
};
export default App;
转载自:https://juejin.cn/post/7254811936289407035