How to save Mobx state in sessionStorage

后端 未结 4 662
无人共我
无人共我 2021-02-13 21:54

Trying to essentially accomplish this https://github.com/elgerlambert/redux-localstorage which is for Redux but do it for Mobx. And preferably would like to use sessionStorage.

相关标签:
4条回答
  • 2021-02-13 22:00

    Posting the example from here: https://mobx.js.org/best/store.html

    This shows a cleaner method of detecting value changes, though not necessarily local storage.

    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();
        }
    }
    
    0 讨论(0)
  • 2021-02-13 22:04

    Turns out you can do this in just a few lines of code:

    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));
    }
    

    Boom. No state lost when I refresh the page. Saves every 500ms if there was a change.

    0 讨论(0)
  • 2021-02-13 22:12

    The easiest way to approach this would be to have a mobx "autorun" triggered whenever any observable property changes. To do that, you could follow my answer to this question.

    I'll put some sample code here that should help you get started:

    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);
      }
    }
    
    0 讨论(0)
  • 2021-02-13 22:17

    Here, you can use my code, although it only supports localStorage you should be able to modify it quite easily.

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

    0 讨论(0)
提交回复
热议问题