首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >转换为anonymousModel时的mobx状态树错误

转换为anonymousModel时的mobx状态树错误
EN

Stack Overflow用户
提问于 2021-01-20 18:47:55
回答 1查看 3.2K关注 0票数 3

应该发生什么-成功地从defaultSnapshot创建RootStore并在需要时重新设置它,在localStorage中成功地备份。--在尝试应用快照时获取错误,尝试打开页面时,只需运行代码,即使不与之交互。

当手动检查类型时,我没有发现类型错误的问题,因此无法理解为什么会抛出错误。

Codesandox活最小编码

误差

代码语言:javascript
运行
复制
Error: [mobx-state-tree] Error while converting `{"token":"","myInnerInfo":{"login":"","type":""},"myDisplayInfo":{"login":"","type":""},"loginInfo":{"login":"","type":""},"loginList":[],"loading":false,"logined":false}` to `AnonymousModel`:

    at path "/myInnerInfo/login" value `""` is not assignable to type: `AnonymousModel` (Value is not a plain object).
    at path "/myInnerInfo/type" value `""` is not assignable to type: `AnonymousModel` (Value is not a plain object).
    at path "/myDisplayInfo/login" value `""` is not assignable to type: `AnonymousModel` (Value is not a plain object).
    at path "/myDisplayInfo/type" value `""` is not assignable to type: `AnonymousModel` (Value is not a plain object).
    at path "/loginInfo/login" value `""` is not assignable to type: `AnonymousModel` (Value is not a plain object).
    at path "/loginInfo/type" value `""` is not assignable to type: `AnonymousModel` (Value is not a plain object).

文件结构

store.js (进口于index.js)

代码语言:javascript
运行
复制
import { types, flow, onSnapshot, applySnapshot } from 'mobx-state-tree';
import { values } from 'mobx';
import axios from 'axios';

const defaultSnapshot = {
  token: '',
  myInnerInfo: { login: '', type: '' },
  myDisplayInfo: { login: '', type: '' },
  loginInfo: { login: '', type: '' },
  loginList: [],
  loading: false,
  logined: false,
}

const User = types
  .model({
    login: '',
    type: '',
  }).actions(self => ({
    setUserInfo({ login, type }) {
      self.login = login;
      self.type = type;
    }
  }))

const RootStore = types
  .model({
    token: '',
    myInnerInfo: types.map(User),
    myDisplayInfo: types.map(User),
    loginInfo: types.map(User),
    loginList: types.array(types.string),
    loading: false,
    logined: false,
  }).views(self => ({
    get loginListLength() {
      return values(self.loginList).length;
    },
  })).actions(self => ({
    // setToken (token) {
    //   self.token = token;
    // },
    // setMyInnerInfo (userInfo) {
    //   self.myInnerInfo.setUserInfo(userInfo);
    // },
    // setMyDisplayInfo (userInfo) {
    //   self.myDisplayInfo.setUserInfo(userInfo);
    // },
    // setLoginInfo (userInfo) {
    //   self.loginInfo.setUserInfo(userInfo);
    // },
    // setLoginList (loginList) {
    //   self.loginList = loginList;
    // },
    // setLoading (loading) {
    //   self.loading = loading;
    // },
    // setLogined (logined) {
    //   self.logined = logined;
    // },
    // reset() {
    //   self.token = '';
    //   self.myInnerInfo = User.create({});
    //   self.myDisplayInfo = User.create({});
    //   self.loginInfo = User.create({});
    //   self.loginList = [];
    //   self.loading = false;
    //   self.logined = false;
    // },
    register: flow(function* register(login, password) {
      self.loading = true;
      try {
        const res = yield axios({
          method: 'POST',
          url: `${process.env.REACT_APP_HOST}/users/register`,
          data: { login, password },
        });
        alert('Registered');
        self.loading=false;
      } catch (e) {
        console.error(e);
        alert(`Error registering! Please retry!`);
        resetStore();
      }
    }),
    login: flow(function* login(login, password) {
      self.loading = true;
      try {
        const res = yield axios({
          method: 'POST',
          url: `${process.env.REACT_APP_HOST}/users/login`,
          data: { login, password },
        });
        self.token = res.data.token;
        self.myInnerInfo.setUserInfo(res.data.user);
        self.myDisplayInfo.setUserInfo({ login: '', type: '' });
        self.loginInfo.setUserInfo({ login: '', type: '' });
        self.loginList = [];
        alert('Logined');
        self.logined = true;
        self.loading=false;
      } catch (e) {
        console.error(e);
        alert(`Error logining! Please retry!`);
        resetStore();
      }
    }),
    unlogin() {
      self.loading = true;
      self.logined = false;
      self.token = '';
      self.myInnerInfo.setUserInfo({ login: '', type: '' });
      self.myDisplayInfo.setUserInfo({ login: '', type: '' });
      self.loginInfo.setUserInfo({ login: '', type: '' });
      self.loginList = [];
      alert('Unlogined');
      self.loading=false;
    },
    getMyInfo: flow(function* getMyInfo() {
      self.loading = true;
      try {
        const res = yield axios({
          method: 'GET',
          url: `${process.env.REACT_APP_HOST}/users/my-info`,
          headers: {'Authorization': self.token ? `Bearer ${self.token}` : ''},
        });
        // self.token = res.data.token;
        // self.myInnerInfo.setUserInfo(res.data.user);
        self.myDisplayInfo.setUserInfo(res.data);
        // self.loginInfo.setUserInfo({});
        // self.loginList = [];
        alert('Loaded information');
        // self.logined = true;
        self.loading=false;
      } catch (e) {
        console.error(e);
        alert(`Error loading information! Please retry!`);
        resetStore();
      }
    }),
    getLoginList: flow(function* getLoginList() {
      self.loading = true;
      try {
        const res = yield axios({
          method: 'GET',
          url: `${process.env.REACT_APP_HOST}/users/list-logins`,
          headers: {'Authorization': self.token ? `Bearer ${self.token}` : ''},
        });
        // self.token = res.data.token;
        // self.myInnerInfo.setUserInfo(res.data.user);
        // self.myDisplayInfo.setUserInfo(res.data);
        // self.loginInfo.setUserInfo({});
        self.loginList = res;
        alert('Loaded list');
        // self.logined = true;
        self.loading=false;
      } catch (e) {
        console.error(e);
        alert(`Error loading list! Please retry!`);
        resetStore();
      }
    }),
    getUserInfo: flow(function* getUserInfo(login) {
      self.loading = true;
      try {
        const res = yield axios({
          method: 'GET',
          url: `${process.env.REACT_APP_HOST}/users/my-info/${login}`,
          headers: {'Authorization': self.token ? `Bearer ${self.token}` : ''},
        });
        // self.token = res.data.token;
        // self.myInnerInfo.setUserInfo(res.data.user);
        // self.myDisplayInfo.setUserInfo(res.data);
        self.loginInfo.setUserInfo(res.data);
        // self.loginList = [];
        alert('Loaded information');
        // self.logined = true;
        self.loading=false;
      } catch (e) {
        console.error(e);
        alert(`Error loading information! Please retry!`);
        resetStore();
      }
    }),
  }));

const store = RootStore.create();

if(!(localStorage[process.env.REACT_APP_LOCALSTORAGE_KEY] && JSON.parse(localStorage[process.env.REACT_APP_LOCALSTORAGE_KEY]))) {
  localStorage[process.env.REACT_APP_LOCALSTORAGE_KEY] = JSON.stringify(defaultSnapshot);
}
applySnapshot(store, JSON.parse(localStorage[process.env.REACT_APP_LOCALSTORAGE_KEY]));

onSnapshot(store, snapshot => {
  localStorage[process.env.REACT_APP_LOCALSTORAGE_KEY] = JSON.stringify(snapshot);
  console.info(snapshot);
});

export default store;
export function resetStore() {
  localStorage[process.env.REACT_APP_LOCALSTORAGE_KEY] = JSON.stringify(defaultSnapshot);
  applySnapshot(store, JSON.parse(localStorage[process.env.REACT_APP_LOCALSTORAGE_KEY]));
}

package.json

代码语言:javascript
运行
复制
{
  "name": "client",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.11.9",
    "@testing-library/react": "^11.2.3",
    "@testing-library/user-event": "^12.6.0",
    "axios": "^0.21.1",
    "mobx": "^6.0.4",
    "mobx-react": "^7.0.5",
    "mobx-state-tree": "^5.0.0",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
    "react-scripts": "4.0.1",
    "web-vitals": "^0.2.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-20 19:58:55

您的defaultSnapshot似乎与您定义的模型结构不匹配。您可以将默认快照定义为:

代码语言:javascript
运行
复制
const defaultSnapshot = {
  token: '',
  myInnerInfo: { login: '', type: '' },
  myDisplayInfo: { login: '', type: '' },
  loginInfo: { login: '', type: '' },
  loginList: [],
  loading: false,
  logined: false,
}

但是,如果在没有参数的情况下创建store之后,您可以获得:

代码语言:javascript
运行
复制
{
 token: "",
 myInnerInfo: {},
 myDisplayInfo: {},
 loginInfo: {},
 loginList: [],
 loading: false,
 logined: false
}

这将是一个“默认快照”,从某种意义上说,这就是当您在没有特定数据的情况下create您的存储所发生的事情。

现在看来,这两个字段应该是兼容的,只不过您将三个Info字段定义为map的。

代码语言:javascript
运行
复制
{
  "<id>": { <model snapshot> },
  …
}

因此,在加载默认快照时,它会导致一个错误,因为它试图将您想要成为模型数据的数据视为地图数据--它认为您有一个包含两个Users的集合,其中键为logintype,值为"",而不是与User兼容的对象。例如,

代码语言:javascript
运行
复制
…
myInnerInfo: { 
  login: { login: 'some user data', type:'' }, 
  type: { login: 'another user data', type:'' }
},
…

会有用,但看起来不像你想要的那样。

您可能打算做的是直接将Info字段设置为User类型,而不是User类型的map,也可能是optionalUser类型,因为在创建存储时不需要指定User。所以也许你的商店模型应该是这样的:

代码语言:javascript
运行
复制
.model({
    token: '',
    myInnerInfo: types.optional(User, {}),
    myDisplayInfo: types.optional(User, {}),
    loginInfo: types.optional(User, {}),
    loginList: types.array(types.string),
    loading: false,
    logined: false,
  })

此结构与默认快照兼容,在创建存储区时不需要值。

注意,原始值是自动可选的,但是模型不是(因此显式optional调用)。optional参数具有默认值,但仍将存在。只是不需要在create时显式地定义它。另外,一定要在测试时重置您的localStorage,否则它可能看起来不工作.

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65815751

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档