在学习mobx中,遇到一个难题弄了几小时也没搞明白inject
,虽然知道这是注入,但不知道正确用法,还是很伤脑筋的。
为了简单的理解所以文件我没有分开管理,也写在同一个文件里方便查看,
项目建立使用creact-react-app
,所以App.js是什么就不多说了。
在不使用inject的时候以下代码都是可以正常运行的。
App.js
import React, { Component } from 'react';
import './App.css';
import { observable, computed } from 'mobx';
import { observer,Provider,inject } from 'mobx-react'
//数据结构
class Todo {
@observable todos = [
{
id: 1,
title: '任务1',
finished: false
}, {
id: 2,
title: '任务2',
finished: false
}
];
@computed get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length;
}
}
@observer
class TodoListView extends Component {
render() {
return (
<div>
<ul>
{this.props.todoList.todos.map(todo =>
<TodoView todo={todo} key={todo.id}/>
)}
</ul>
未完成任务数:{this.props.todoList.unfinishedTodoCount}
</div>
)
}
}
@observer
class TodoView extends Component {
componentWillReact() {
console.log('I will re-render, since the todo has changed!');
}
render() {
// return <div>{this.props.todo.title}</div>;
var todo = this.props.todo;
return (
<li>
<label>
<input
type="checkbox"
checked={todo.finished}
onClick={() => todo.finished = !todo.finished}
/>
{todo.title}
</label>
</li>
)
}
}
const todoList = new Todo();
class App extends Component{
render(){
return (
<div>
<TodoListView todoList={todoList}/>
</div>
);
}
}
export default App;
通过简单的修改对App添加了inject
,修改后的代码如下:
//以上代码不变,
@inject('todoList')
class App extends Component{
render(){
return (
<div>
<TodoListView todoList={this.props.todoList}/>
</div>
);
}
}
你会看到以下报错信息:
Error: MobX injector: Store 'todoList' is not available! Make sure it is provided by some Provider
从报错信息可以知道需要一个Provider
于是傻傻的写下以下代码:
@inject('todoList')
class App extends Component{
render(){
return (
<Provider>
<div>
<TodoListView todoList={this.props.todoList}/>
</div>
</Provider>
);
}
}
但还是报同样的错误信息,这个头大了,不知道怎么搞了。唯一的办法就是冷静下来,认真思考
在好好思考后发现问题所在:injector
本身需要一个Provider
,我又把写到inject
里面,这完全没有用的,看来是写反了,应该是一个Provider
为根才对。想清楚这点后,开始改造。
@inject('todoList')
class ToDoApp extends Component{
render(){
return (
<div>
<TodoListView todoList={this.props.todoList}/>
</div>
);
}
}
class App extends Component{
render(){
return(
<Provider todoList={todoList}>
<ToDoApp/>
</Provider>
)
}
}
尝试一下成功了,^_^。
完整代码如下:
import React, { Component } from 'react';
import './App.css';
import { observable, computed } from 'mobx';
import { observer,Provider,inject } from 'mobx-react'
//数据结构
class Todo {
@observable todos = [
{
id: 1,
title: '任务1',
finished: false
}, {
id: 2,
title: '任务2',
finished: false
}
];
@computed get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length;
}
}
@observer
class TodoListView extends Component {
render() {
return (
<div>
<ul>
{this.props.todoList.todos.map(todo =>
<TodoView todo={todo} key={todo.id}/>
)}
</ul>
未完成任务数:{this.props.todoList.unfinishedTodoCount}
</div>
)
}
}
@observer
class TodoView extends Component {
componentWillReact() {
console.log('I will re-render, since the todo has changed!');
}
render() {
// return <div>{this.props.todo.title}</div>;
var todo = this.props.todo;
return (
<li>
<label>
<input
type="checkbox"
checked={todo.finished}
onClick={() => todo.finished = !todo.finished}
/>
{todo.title}
</label>
</li>
)
}
}
const todoList = new Todo();
@inject('todoList')
class ToDoApp extends Component{
render(){
return (
<div>
<TodoListView todoList={this.props.todoList}/>
</div>
);
}
}
class App extends Component{
render(){
return(
<Provider todoList={todoList}>
<ToDoApp/>
</Provider>
)
}
}
export default App;
想了想,如果不使用inject
全是什么情况呢?
// @inject('todoList')
class ToDoApp extends Component{
render(){
return (
<div>
<TodoListView todoList={this.props.todoList}/>
</div>
);
}
}
class App extends Component{
render(){
return(
<Provider>
<ToDoApp todoList={todoList}/>
</Provider>
)
}
}
通过修改不难发现
-
Provider
为根 - 如果不使用
Provider
配合inject
的话,代码相对多一些,需要自己的管理 - 如果使用
Provider
配合inject
,就没有那么麻烦了,把多个store,配到根上,子组件通过inject
自动注入。
以下为简单应用:
import React, { Component } from 'react';
import './App.css';
import { observable, computed } from 'mobx';
import { observer,Provider,inject } from 'mobx-react'
//数据结构
class Todo {
@observable todos = [
{
id: 1,
title: '任务1',
finished: false
}, {
id: 2,
title: '任务2',
finished: false
}
];
@computed get unfinishedTodoCount() {
return this.todos.filter(todo => !todo.finished).length;
}
}
@observer
class TodoListView extends Component {
delClick = (todo)=>{
this.props.todoList.todos.remove(todo);
};
render() {
return (
<div>
<ul>
{this.props.todoList.todos.map(todo =>
<TodoView todo={todo} delClick={this.delClick} key={todo.id}/>
)}
</ul>
未完成任务数:{this.props.todoList.unfinishedTodoCount}
</div>
)
}
}
@observer
class TodoView extends Component {
componentWillReact() {
console.log('I will re-render, since the todo has changed!');
}
render() {
var todo = this.props.todo;
return (
<li>
<label>
<input
type="checkbox"
checked={todo.finished}
onClick={() => todo.finished = !todo.finished}
/>
{todo.title}
</label>
<button onClick={() => {this.props.delClick(todo)}}>del</button>
</li>
)
}
}
const todoList = new Todo();
@inject('todoList')
class ToDoApp extends Component{
render(){
return (
<div>
<TodoListView todoList={this.props.todoList}/>
</div>
);
}
}
@inject('todoList')
@observer
class ToDoAdd extends Component{
todoList = this.props.todoList;
add=()=>{
const title = this.refs.task.value;
if(!title.length){
alert('任务名字不能为空');
return;
}
todoList.todos.push({
id: 3, //临时
title: this.refs.task.value,
finished: false
})
};
render(){
return(
<div>
<input type="text" ref='task'/>
<button onClick={this.add}>添加</button>
</div>
)
}
}
class App extends Component{
render(){
return(
<Provider todoList={todoList}>
<div>
<ToDoAdd />
<ToDoApp />
</div>
</Provider>
)
}
}
export default App;
6E0269DC-9114-4F78-A575-8B7FDA65DEDA.png