【问题标题】:How to save Mobx state in sessionStorage如何在 sessionStorage 中保存 Mobx 状态
【发布时间】:2016-10-27 19:23:11
【问题描述】:

试图从本质上完成这个https://github.com/elgerlambert/redux-localstorage,它适用于 Redux,但适用于 Mobx。而且最好是想用sessionStorage。有没有一种简单的方法可以用最少的样板来实现这一点?

【问题讨论】:

    标签: reactjs mobx mobx-react


    【解决方案1】:

    解决这个问题的最简单方法是在任何可观察属性发生变化时触发 mobx“自动运行”。为此,您可以关注my answer to this question

    我将在此处放置一些示例代码,以帮助您入门:

    function autoSave(store, save) {
      let firstRun = true;
      mobx.autorun(() => {
        // This code will run every time any observable property
        // on the store is updated.
        const json = JSON.stringify(mobx.toJS(store));
        if (!firstRun) {
          save(json);
        }
        firstRun = false;
      });
    }
    
    class MyStore {
      @mobx.observable prop1 = 999;
      @mobx.observable prop2 = [100, 200];
    
      constructor() {
        this.load();
        autoSave(this, this.save.bind(this));
      }
    
      load() {
        if (/* there is data in sessionStorage */) {
          const data = /* somehow get the data from sessionStorage or anywhere else */;
          mobx.extendObservable(this, data);
        }
      }
    
      save(json) {
        // Now you can do whatever you want with `json`.
        // e.g. save it to session storage.
        alert(json);
      }
    }
    

    【讨论】:

    • 谢谢!它如何在页面重新加载时重新加载状态?
    • 在构造函数中,在调用autoSave()之前,您可以从 sessionStorage 中读取并设置存储实例的值。
    • 我刚刚编辑了我的答案以提供更完整的解决方案。当然,您仍然需要进行一些更改才能使其适用于您的情况,但我希望这可以帮助您入门。
    • 加载时遇到Error: [mobx] 'extendObservable' can only be used to introduce new properties. Use 'set' or 'decorate' instead
    【解决方案2】:

    从这里发布示例:https://mobx.js.org/best/store.html

    这显示了一种更简洁的检测值变化的方法,尽管不一定是本地存储。

    import {observable, autorun} from 'mobx';
    import uuid from 'node-uuid';
    
    export class TodoStore {
        authorStore;
        transportLayer;
        @observable todos = [];
        @observable isLoading = true;
    
        constructor(transportLayer, authorStore) {
            this.authorStore = authorStore; // Store that can resolve authors for us
            this.transportLayer = transportLayer; // Thing that can make server requests for us
            this.transportLayer.onReceiveTodoUpdate(updatedTodo => this.updateTodoFromServer(updatedTodo));
            this.loadTodos();
        }
    
        /**
         * Fetches all todo's from the server
         */
        loadTodos() {
            this.isLoading = true;
            this.transportLayer.fetchTodos().then(fetchedTodos => {
                fetchedTodos.forEach(json => this.updateTodoFromServer(json));
                this.isLoading = false;
            });
        }
    
        /**
         * Update a todo with information from the server. Guarantees a todo
         * only exists once. Might either construct a new todo, update an existing one,
         * or remove an todo if it has been deleted on the server.
         */
        updateTodoFromServer(json) {
            var todo = this.todos.find(todo => todo.id === json.id);
            if (!todo) {
                todo = new Todo(this, json.id);
                this.todos.push(todo);
            }
            if (json.isDeleted) {
                this.removeTodo(todo);
            } else {
                todo.updateFromJson(json);
            }
        }
    
        /**
         * Creates a fresh todo on the client and server
         */
        createTodo() {
            var todo = new Todo(this);
            this.todos.push(todo);
            return todo;
        }
    
        /**
         * A todo was somehow deleted, clean it from the client memory
         */
        removeTodo(todo) {
            this.todos.splice(this.todos.indexOf(todo), 1);
            todo.dispose();
        }
    }
    
    export class Todo {
    
        /**
         * unique id of this todo, immutable.
         */
        id = null;
    
        @observable completed = false;
        @observable task = "";
    
        /**
         * reference to an Author object (from the authorStore)
         */
        @observable author = null;
    
        store = null;
    
        /**
         * Indicates whether changes in this object
         * should be submitted to the server
         */
        autoSave = true;
    
        /**
         * Disposer for the side effect that automatically
         * stores this Todo, see @dispose.
         */
        saveHandler = null;
    
        constructor(store, id=uuid.v4()) {
            this.store = store;
            this.id = id;
    
            this.saveHandler = reaction(
                // observe everything that is used in the JSON:
                () => this.asJson,
                // if autoSave is on, send json to server
                (json) => {
                    if (this.autoSave) {
                        this.store.transportLayer.saveTodo(json);
                    }
                }
            );
        }
    
        /**
         * Remove this todo from the client and server
         */
        delete() {
            this.store.transportLayer.deleteTodo(this.id);
            this.store.removeTodo(this);
        }
    
        @computed get asJson() {
            return {
                id: this.id,
                completed: this.completed,
                task: this.task,
                authorId: this.author ? this.author.id : null
            };
        }
    
        /**
         * Update this todo with information from the server
         */
        updateFromJson(json) {
            // make sure our changes aren't send back to the server
            this.autoSave = false;
            this.completed = json.completed;
            this.task = json.task;
            this.author = this.store.authorStore.resolveAuthor(json.authorId);
            this.autoSave = true;
        }
    
        dispose() {
            // clean up the observer
            this.saveHandler();
        }
    }
    

    【讨论】:

      【解决方案3】:

      事实证明,您只需几行代码就可以做到这一点:

      const store = observable({
          players: [
              "Player 1",
              "Player 2",
          ],
          // ...
      })
      
      reaction(() => JSON.stringify(store), json => {
          localStorage.setItem('store',json);
      }, {
          delay: 500,
      });
      
      let json = localStorage.getItem('store');
      if(json) {
          Object.assign(store, JSON.parse(json));
      }
      

      轰隆隆。刷新页面时没有状态丢失。如果有变化,每 500 毫秒保存一次。

      【讨论】:

      • 如果启用了严格模式,则会报错,changing observed observable values outside actions is not allowed
      • @karianpour 我想你只需要把它包装在action(() => Object.assign(...))) 然后
      【解决方案4】:

      在这里,你可以使用我的代码,虽然它只支持 localStorage 你应该可以很容易地修改它。

      https://github.com/nightwolfz/mobx-storage

      【讨论】:

        猜你喜欢
        • 2021-01-13
        • 1970-01-01
        • 1970-01-01
        • 2022-01-19
        • 1970-01-01
        • 1970-01-01
        • 2011-09-05
        • 2017-11-12
        • 2014-02-08
        相关资源
        最近更新 更多