我正在尝试使用react-native和zustand persist实现一个简单的todo应用程序,没有
persist
方法的代码工作正常,但是当我尝试引入persist时,我遇到了错误或者我无法正确实现它,我浏览了 zustand 页面上的文档,但它不起作用。下面是相关代码和错误:
应用程序.tsx
const App = () => {
const { todos, addTodo, getTodos } = useTodoStore((state: TodoState) => state);
useEffect(() => {
getTodos();
}, []);
return (
...
)
}
zustand店:
import create from 'zustand';
import { persist } from 'zustand/middleware';
import AsynStorage from '@react-native-async-storage/async-storage';
export interface Todo {
id: string;
text: string;
completed: boolean;
createdAt: string;
}
export interface TodoState {
todos: Todo[];
addTodo: (todo: Todo) => void;
getTodos: () => void;
removeTodo: (id: string) => void;
toggleTodo: (id: string) => void;
}
export const useTodoStore = create<TodoState>(
// @ts-ignore
persist(
set => ({
todos: [],
getTodos: () => {
AsynStorage.getItem('todo-storage').then(todos => {
if (todos) {
set(state => ({ ...state, todos: JSON.parse(todos) }));
}
});
},
addTodo: (todo: Todo) => {
set(state => {
console.log('state: ', state.todos);
return {
...state,
todos: [...state.todos, todo],
};
});
},
removeTodo: (id: string) => {
set(state => ({
...state,
todos: state.todos.filter(todo => todo.id !== id),
}));
},
toggleTodo: (id: string) => {
set(state => ({
...state,
todos: state.todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo,
),
}));
},
}),
{
name: 'todo-storage',
getStorage: () => AsynStorage,
},
),
);
现在,当我尝试添加待办事项时,遇到以下错误:
ERROR TypeError: Invalid attempt to spread non-iterable instance.
In order to be iterable, non-array objects must have a [Symbol.iterator]() method.
那么,有没有人有持久化(react-native)的代码示例,我不明白我在这里做错了什么,我正在按照文档中所示进行操作。
编辑: 如果我删除
persist
中间件以及与其相关的所有代码,它也可以正常工作,还要注意:
当我将
persist
中间件与async-storage
一起使用时,状态是这样的:
LOG state: {"state": {"_hasHydrated": true, "todos": {"state": [Object], "version": 0}}, "version": 0}
当我不使用
persist
时它会起作用:
LOG state: [{"completed": false, "createdAt": "Fri Jul 22 2022 14:27:47 GMT+0530 (IST)", "id": "6bfdab5e34b198", "text": "Let’s seeeee"}]
我不知道 zustand 如何处理网络上默认存储以外的存储,但我假设 API 可能与react-native-async-storage 不匹配。我建议您手动实现存储的 get 和 set 方法,就像它们在此处的文档中所解释的那样:https://github.com/pmndrs/zustand/blob/main/docs/integrations/persisting-store-data。 md#如何使用自定义存储引擎
我还没有尝试运行你的代码。但是,您不需要手动调用
AsyncStorage.getItem()
来恢复已保存的商店。 persist
中间件可以处理这个问题。 getTodos
,我怀疑这是错误的行为,因此是不必要的。我进一步怀疑 zustand persist
向序列化数据添加了额外的元数据,这就是您手动注销时看到的内容。
请参阅此示例了解一般结构(已省略操作)。
这是对原始问题的完整答案。
import { create } from "zustand";
import { persist, createJSONStorage, StateStorage } from "zustand/middleware";
import AsyncStorage from "@react-native-async-storage/async-storage";
const storage: StateStorage = {
getItem: async (name: string): Promise<string | null> => {
console.log(name, "has been retrieved");
const data = (await AsyncStorage.getItem(name)) || null;
console.log("data: ", data);
return data;
},
setItem: async (name: string, value: string): Promise<void> => {
console.log(name, "with value", value, "has been saved");
await AsyncStorage.setItem(name, value);
},
removeItem: async (name: string): Promise<void> => {
console.log(name, "has been deleted");
await AsyncStorage.removeItem(name);
},
};
export interface Todo {
id: string;
text: string;
completed: boolean;
createdAt: string;
}
export interface TodoState {
todos: Todo[];
add: (todo: Todo) => void;
remove: (id: string) => void;
toggle: (id: string) => void;
}
export const useTodoStore = create<TodoState>()(
persist(
(set) => ({
todos: [],
add: (todo: Todo) => {
set((state) => {
console.log("state: ", state.todos);
return {
...state,
todos: [...state.todos, todo],
};
});
},
remove: (id: string) => {
set((state) => ({
...state,
todos: state.todos.filter((todo) => todo.id !== id),
}));
},
toggle: (id: string) => {
set((state) => ({
...state,
todos: state.todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
),
}));
},
}),
{
name: "todo-storage",
storage: createJSONStorage(() => storage),
}
)
);
上面的代码使用 AsyncStorage for zustand 创建自定义存储。
我知道,我参加聚会迟到了,但这可能会对某人有所帮助。