原文: Mobx React — Best Practices
在本文中,我将展示React与mobx结合使用的常见最佳实践。我将按规则介绍它们。因此,每当遇到特定问题时,都应遵循这些规则来尝试解决。
本文要求你对mobx中的store有基本的了解。如果没有,请先阅读此内容。
目录
用store表示ui状态
切记,store表示你的的应用程序的ui状态。这意味着,当你将store的状态保存到文件中时,关闭程序并以加载的状态重新启动它,你将拥有相同的程序,并且会看到与关闭程序之前相同的内容。store并不意味着是“本地数据库”。它们还保存有关哪些按钮可见,已禁用,输入字段的当前文本等信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class SearchStore { @observable searchText; @action setSearchText = (searchText) => { this.searchText = searchText } } @observer class SearchInput extends React.Component { handleInputChanged = (event) => { const { searchStore } = this.props; searchStore.setSearchText(event.target.value); } render() { const { searchStore } = this.props; return ( <input value={searchStore.searchText} onChange={this.handleInputChanged} /> ); } } |
将接口调用和store分离
不要在store内调用rest接口,这会使它们难以测试。而是将这些接口调用放入额外的类中,然后使用store的构造函数将这些实例传递给每个store。编写测试时,您可以轻松地伪造这些api调用,并将伪造的api实例传递给每个store。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
class TodoApi { fetchTodos = () => request.get('/todos') } class TodoStore { @observable todos = []; constructor(todoApi) { this.todoApi = todoApi; } fetchTodos = async () => { const todos = await this.todoApi.fetchTodos(); runInAction(() => { this.todos = todos; }); } } // Then in your main const todoApi = new TodoApi(); const todoStore = new TodoStore(todoApi); |
将业务逻辑保存在store中
永远不要在组件中编写业务逻辑。当你在组件中编写业务逻辑时,你没有机会重用它,你的业务逻辑会散布在许多组件中,这使得重构或重用代码变得很困难。使用store中的方法编写业务逻辑,然后从组件中调用这些方法。
不要创建全局Store实例
永远不要创建全局store实例。你将不能为组件编写任何合理且可靠的测试。而是使用Provider将你的store注入到组件prop中。然后,在测试中,你可以轻松模拟这些store。
1 2 3 4 5 6 7 8 9 |
const searchStore = new SearchStore(); const app = ( <Provider searchStore={searchStore}> <SearchInput /> </Provider> ); ReactDom.render(app, container); |
只允许store更改其属性
切勿直接在组件中更改store的属性。只允许store更改其自己的属性。始终从store中调用一个方法,该方法会更改store的属性。否则,你的应用程序状态(store=application state)会随处更新,并且你正在慢慢失去控制权。这使得调试非常困难。
始终使用@observer装饰每个组件
使用@observer装饰每个组件可以使每个组件在store属性更改时进行更新。否则,需要重新渲染以@observer装饰的父组件,以更新其子组件。因此,需要重新渲染的组件更少。
使用 @computed
假设你要在用户没有管理员角色并且应用程序不在“管理员模式”时禁用按钮。在一个store中,像isAdmin这样的单个属性还不够。你的store中将需要一个计算属性。
1 2 3 4 5 6 7 8 9 10 |
class ApplicationStore { @observable loggedInUser; @observable isInAdminMode; @computed isAdminButtonEnabled = () => { return this.loggedInUser.role === 'admin' && this.isInAdminMode; } } |
你可能不需要React Router
你可能不需要react router。正如我之前说过的,你希望store表示你的应用程序状态。当你让React Router处理部分应用程序状态时,请勿让你的store表示应用程序状态。因此,将当前显示的视图保留在其中一个store的一个属性中。然后,你只有一个用来渲染属性内容的组件。
如何解耦状态和组件–你不需要componentWillMount
尝试偏向受控组件而不是不受控制组件
始终尝试构建受控组件。这会使得测试组件和组件的整体复杂性易于处理。
希望这些简单的技巧对你有所帮助。
有点牛逼,博客更新坚持到了去年12月,不错不错。今年也加油啊。