用 zustand 坚持本机反应

问题描述 投票:0回答:3

我正在尝试使用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"}]
javascript react-native zustand
3个回答
2
投票

我不知道 zustand 如何处理网络上默认存储以外的存储,但我假设 API 可能与react-native-async-storage 不匹配。我建议您手动实现存储的 get 和 set 方法,就像它们在此处的文档中所解释的那样:https://github.com/pmndrs/zustand/blob/main/docs/integrations/persisting-store-data。 md#如何使用自定义存储引擎


0
投票

我还没有尝试运行你的代码。但是,您不需要手动调用

AsyncStorage.getItem()
来恢复已保存的商店。
persist
中间件可以处理这个问题。
getTodos
,我怀疑这是错误的行为,因此是不必要的。我进一步怀疑 zustand
persist
向序列化数据添加了额外的元数据,这就是您手动注销时看到的内容。

请参阅此示例了解一般结构(已省略操作)。


0
投票

这是对原始问题的完整答案。

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 创建自定义存储。

我知道,我参加聚会迟到了,但这可能会对某人有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.