如何解决转换为匿名模型时出现 mobx-state-tree 错误
应该发生什么 - 从 defaultSnapshot 成功创建 RootStore 并在需要时重置它,在 localStorage 中成功备份。 发生了什么 - 在尝试应用快照时、在尝试打开页面时出现错误,即使没有与之交互也只是通过运行代码。
手动检查类型时,我没有看到类型错误的问题,所以无法理解为什么会抛出错误。
Error: [mobx-state-tree] Error while converting `{"token":"","myInnerInfo":{"login":"","type":""},"mydisplayInfo":{"login":"","loginInfo":{"login":"","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 中导入)
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: '',loginInfo: { login: '',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),}).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,url: `${process.env.REACT_APP_HOST}/users/login`,});
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`,});
// 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}`,});
// 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
{
"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"
]
}
}
解决方法
您的 defaultSnapshot
似乎与您定义的模型结构不匹配。
您可以按如下方式定义默认快照:
const defaultSnapshot = {
token: '',myInnerInfo: { login: '',type: '' },myDisplayInfo: { login: '',loginInfo: { login: '',loginList: [],loading: false,logined: false,}
但是,如果您在没有参数的情况下创建 getSnapshot
之后的 store
,您会得到:
{
token: "",myInnerInfo: {},myDisplayInfo: {},loginInfo: {},logined: false
}
这将是“默认快照”,因为它是当您create
没有特定数据的商店时会发生的情况。
现在看起来两者应该是兼容的,只是您将三个 Info
字段定义为 map
。模型图如下所示:
{
"<id>": { <model snapshot> },…
}
因此,在加载您的默认快照时,它会导致错误,因为它试图将您打算作为模型数据的内容视为地图数据 - 它认为您有两个 Users
的集合,键为 {{1 }} 和 login
,以及 type
的值,而不是与 ""
兼容的对象。例如,
User
可以,但似乎不是您想要的。
您可能打算做的是将 …
myInnerInfo: {
login: { login: 'some user data',type:'' },type: { login: 'another user data',type:'' }
},…
字段直接设为 Info
类型,而不是 User
类型的 map
,或者可能是 {{1} }} 或 User
类型,此后您无需在创建商店时指定 optional
。所以也许你的商店模型应该是这样的:
User
此结构与您的默认快照兼容,并且在创建商店时不需要值。
请注意,原始值是自动可选的,但模型不是(因此显式调用 User
的原因)。 .model({
token: '',myInnerInfo: types.optional(User,{}),myDisplayInfo: types.optional(User,loginInfo: types.optional(User,loginList: types.array(types.string),})
参数具有默认值,但仍将存在。它只是不需要在 optional
时间明确定义。另外,请务必在测试时重置您的 optional
,否则它可能看起来不起作用...
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。