视图层重构
视图层的重构工作主要是使用 observer/@observer 将组件转换成一个个 reaction,同时使用 mobx-react 提供的 inject/@inject 注入组件所需的 store。
首先,在组件树的最外层使用 mobx-react 提供的 Provider 组件注入合并后的 store:
import React from "react";
import ReactDOM from "react-dom";
import { useStrict } from 'mobx';
import { Provider } from "mobx-react";
import App from "./components/App";
import stores from "./stores";
// 在严格模式下,运行MobX
useStrict(true);
ReactDOM.render(
<Provider {...stores}>
<App />
</Provider>,
document.getElementById("root")
);
组件 App 需要使用 appStore,主要代码如下:
@inject("appStore") // @inject 注入使用的 Store: appStore
@observer // @observer 把 App 组件转化成一个 reaction,自动响应 state 的变化
class App extends Component {
// ...
render() {
const {error, isLoading, removeError} = this.props.appStore;
const errorDialog = error && (
<ModalDialog onClose={removeError}>{error.message || error}</ModalDialog>
);
return (
<div>
<Router>
<Switch>
<Route exact path="/" component={AsyncHome}/>
<Route path="/login" component={AsyncLogin}/>
<Route path="/posts" component={AsyncHome}/>
</Switch>
</Router>
{errorDialog}
{isLoading && <Loading/>}
</div>
);
}
}
export default App;
再来看一下组件 PostList,它需要使用 postsStore、authStore 和 uiStore 三个 store,代码如下:
import React, {Component} from "react";
import {inject, observer} from "mobx-react";
import PostsView from "./PostsView";
import PostEditor from "../Post/PostEditor";
import "./style.css";
@inject("postsStore", "authStore", "uiStore")
@observer
class PostList extends Component {
componentDidMount() {
// 获取帖子列表
this.props.postsStore.fetchPostList();
}
// 保存新建的帖子
handleSave = data => {
this.props.postsStore
.createPost(data)
.then(() => this.props.uiStore.setAddDialogStatus(false));
};
// 取消新建帖子的状态
handleCancel = () => {
this.props.uiStore.setAddDialogStatus(false);
};
// 设置新建帖子的状态
handleNewPost = () => {
this.props.uiStore.setAddDialogStatus(true);
};
render() {
const {postsStore, authStore, uiStore} = this.props;
return (
<div className="postList">
<div>
<h2>帖子列表</h2>
{authStore.userId ? (
<button onClick={this.handleNewPost}>发帖</button>
) : null}
</div>
{uiStore.addDialogOpen ? (
<PostEditor onSave={this.handleSave} onCancel={this.handleCancel}/>
) : null}
<PostsView posts={postsStore.posts}/>
</div>
);
}
}
export default PostList;
其他组件的改造也都类似,为节约篇幅,这里不再一一介绍,请读者参考源代码。