我正在使用 Mobx 来创建可观察状态。
这是我的代码片段:
window.sessionStorage.setItem(createKey(key), JSON.stringify(state))
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,“状态”对象是可观察的。当我尝试将其转换为字符串时,出现错误:
错误:无法读取未定义的属性“atom”
让我们假设有一个TodosStore看起来像这样的单例:
class TodosStore {
@observable isLoading;
@observable todos;
@action.bound fetchTodos() {
this.isLoading = true;
return api.getTodos().then(todos => this.todos = todos)
.finally(()=>this.isLoading=false);
}
getTodoById(id) {
return this.todos.find(todo => todo.id === id);
}
}
Run Code Online (Sandbox Code Playgroud)
我们还假设有一个使用 URL 表示状态的待办事项详细信息视图,例如/todos/123。
@observer class TodoDetail extends React.Component {
constructor(props){
TodosStore.fetchTodos().then(
this.todo = TodosStore.getTodoById(props.subscriptionId);
);
}
render(){
return (
<div>
{TodosStore.isLoading ?
'Loading, please wait...' :
<h1>this.todo.text</h1>
}
</div>
);
}
}
Run Code Online (Sandbox Code Playgroud)
所以,this.todo显然不是反应性的,所以设置它不会重新运行render()。
一种选择是在视图代码中创建一个@observable todo;,但我宁愿将 mobx 助手保留在视图之外。
请问有更好的方法吗?
我有一个 axios 拦截器,当用户被强制注销(由于令牌过期)时,我想返回我的主页。
我不确定如何将反应路由器传递给它。我正在使用 mobx,但不确定这是否能帮助我解决这个问题。
export const axiosInstance = axios.create({
baseURL: 'https://localhost:44391/api',
timeout: 5000,
contentType: "application/json",
Authorization: getAuthToken()
})
axiosInstance.interceptors.response.use(function (response) {
return response;
}, function (error) {
const originalRequest = error.config;
if(error.code != "ECONNABORTED" && error.response.status === 401 && !originalRequest._retry){
originalRequest._retry = true;
return axiosInstance.post("/tokens/auth",{
"refreshToken": getRefreshToken(),
"grantType": "refresh_token"
}).then(response => {
localStorage.authentication = JSON.stringify(response.data);
updateAuthInstant();
return axiosInstance(originalRequest)
});
}
return Promise.reject(error);
});
Run Code Online (Sandbox Code Playgroud) 通过下面的代码我得到这个错误:
error: Error: [mobx-state-tree] Cannot modify
'AuthenticationStore@<root>', the object is protected and can only be
modified by using an action.
Run Code Online (Sandbox Code Playgroud)
有问题的代码(生成器):
.model('AuthenticationStore', {
user: types.frozen(),
loading: types.optional(types.boolean, false),
error: types.frozen()
})
.actions(self => ({
submitLogin: flow(function * (email, password) {
self.error = undefined
self.loading = true
self.user = yield fetch('/api/sign_in', {
method: 'post',
mode: 'cors',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
'user' : {
'email': email,
'password': password
}
})
}).then(res => {
return res.json()
}).then(response => {
self.loading …Run Code Online (Sandbox Code Playgroud) 即使在阅读了文档之后,我也试图了解 mobx 中动作装饰器的有用性,https://mobx.js.org/refguide/action.html
仍然想知道为什么我应该使用 @action 或 @action.bound,而不是强制执行组件无法直接更改可观察值的模式。
上面的文章提到提供“有用的调试信息”。但我在哪里可以找到这些信息呢?调用 @action 或 @action.bound 方法时,F12->Console 不显示任何内容。
或者我在下面的代码中做错了什么?
我应该安装一些 mobx 调试器吗?谢谢。
class CommentStore {
@observable commentData = [];
@action.bound
updateComment(id, name) {
this.commentData.map(p => p.id === id ? p.name = name : p.name = p.name);
}
...
Run Code Online (Sandbox Code Playgroud) 我有一篇文章是 mobx-state-tree 对象,我在 React 应用程序中使用它。
这是我的树内的一个动作
setId(id: string) {
self.id = id
this.updateProduct()
},
Run Code Online (Sandbox Code Playgroud)
还有活动
<input
value={comp.productId}
onChange={(e) => comp.setId(e.target.value)}
/>
Run Code Online (Sandbox Code Playgroud)
问题是this.updateProduct()每次更改都会运行,并在每次按键后进行异步调用。
我想利用 mobx 反应并使用类似的东西
reaction(
() => ({
id: this.id
}),
() => {
this.updateProduct()
}, {
delay: 500 // this is the key thing
})
Run Code Online (Sandbox Code Playgroud)
我发现延迟在这种情况下非常有用,所以我想在树内使用它们。
在 mobx 状态树中添加反应是一个好习惯吗?如果是,使用反应的正确位置在哪里?
我可以在反应组件内定义反应,但它将在树之外。在树外面是个好习惯吗?
这是我的简化商店:
export class ProfileStore {
profile = {
id: 1,
name: "Tommy",
todos: [
{
value: "Clean the room",
done: false
}
]
};
constructor() {
makeObservable(this, {
profile: observable,
});
}
}
Run Code Online (Sandbox Code Playgroud)
我的目标是倾听可观察到的“配置文件”内的每一个可能的变化。我想使用reactionMobX 来实现此目的,但这有点棘手。
reaction(
() => this.profile,
() => {
console.log("change");
}
);
Run Code Online (Sandbox Code Playgroud)
上面的示例根本不起作用,因为 MobX 不会对值做出反应,而是对属性和引用做出反应。所以我把它改成这样:
reaction(
() => ({
id: this.profile.id,
name: this.profile.name,
todos: this.profile.todos.slice()
}),
() => {
console.log("change");
}
);
Run Code Online (Sandbox Code Playgroud)
它开始起作用,但并不完全起作用。除了切换待办事项中的属性之外,它还会监听所有更改done。如果我添加另一个属性,我需要在这里列出,这有点乏味。
处理这个问题的最佳方法是什么?如何应对每一个可能的变化?
我为此制作了一个codesandbox:链接
尝试按下按钮并查看计数器。
我有一个MobX观察到的数组,我想删除与lodash的多个元素删除.这会导致重新渲染数组中的每个元素.
const array = observable([1,2,3,4,5,1]);
const App = observer(() => {
console.log('Rendering...');
return (
<div>
{ array.map(e => <div> {e} </div>)}
</div>
);
});
ReactDOM.render(
<App />,
document.getElementById('app')
);
Run Code Online (Sandbox Code Playgroud)
如果我尝试删除每次出现的事件1,Rendering...则会为每个元素记录一次:
_.remove(array, num => num === 1);
> "Rendering..."
> "Rendering..."
> "Rendering..."
> "Rendering..."
> "Rendering..."
> "Rendering..."
Run Code Online (Sandbox Code Playgroud)
我该怎么做才能重新渲染一次?
我试图设置一个“管理员”页面,该页面只能由用户“级别”大于2的人员访问。我正在使用MobX和React-Router。该问题可能是由于我不知道如何正确连接到MobX存储而引起的。我正在导入一个名为isAdmin的函数,该函数位于route.js的单独文件中。该函数如下所示:
export const isAdmin = (nextState, replace) => {
const user = this.context.store.auth.user;
if (user.level < 2 || !user) {
replace({
pathname: '/',
});
}
};
Run Code Online (Sandbox Code Playgroud)
这大致基于gitHub页面上最后一个示例,该示例位于此处的react-router。
谢谢你的帮助!
为什么MobX不能用作国家容器?官方文档中提到"MobX不是国家容器"?是不是像Redux?
mobx ×10
reactjs ×6
mobx-react ×5
javascript ×3
react-router ×3
axios ×1
feathersjs ×1
generator ×1
history ×1
lodash ×1