在學(xué)習(xí)mobx中,遇到一個(gè)難題弄了幾小時(shí)也沒搞明白inject,雖然知道這是注入,但不知道正確用法,還是很傷腦筋的。
為了簡單的理解所以文件我沒有分開管理,也寫在同一個(gè)文件里方便查看,
項(xiàng)目建立使用creact-react-app,所以App.js是什么就不多說了。
在不使用inject的時(shí)候以下代碼都是可以正常運(yùn)行的。
App.js
import React, { Component } from 'react';
import './App.css';
import { observable, computed } from 'mobx';
import { observer,Provider,inject } from 'mobx-react'
//數(shù)據(jù)結(jié)構(gòu)
class Todo {
@observable todos = [
{
id: 1,
title: '任務(wù)1',
finished: false
}, {
id: 2,
title: '任務(wù)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>
未完成任務(wù)數(shù):{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>
);
}
}
你會(huì)看到以下報(bào)錯(cuò)信息:
Error: MobX injector: Store 'todoList' is not available! Make sure it is provided by some Provider
從報(bào)錯(cuò)信息可以知道需要一個(gè)Provider
于是傻傻的寫下以下代碼:
@inject('todoList')
class App extends Component{
render(){
return (
<Provider>
<div>
<TodoListView todoList={this.props.todoList}/>
</div>
</Provider>
);
}
}
但還是報(bào)同樣的錯(cuò)誤信息,這個(gè)頭大了,不知道怎么搞了。唯一的辦法就是冷靜下來,認(rèn)真思考
在好好思考后發(fā)現(xiàn)問題所在:injector本身需要一個(gè)Provider,我又把寫到inject里面,這完全沒有用的,看來是寫反了,應(yīng)該是一個(gè)Provider為根才對。想清楚這點(diǎn)后,開始改造。
@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'
//數(shù)據(jù)結(jié)構(gòu)
class Todo {
@observable todos = [
{
id: 1,
title: '任務(wù)1',
finished: false
}, {
id: 2,
title: '任務(wù)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>
未完成任務(wù)數(shù):{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>
)
}
}
通過修改不難發(fā)現(xiàn)
-
Provider為根 - 如果不使用
Provider配合inject的話,代碼相對多一些,需要自己的管理 - 如果使用
Provider配合inject,就沒有那么麻煩了,把多個(gè)store,配到根上,子組件通過inject自動(dòng)注入。
以下為簡單應(yīng)用:
import React, { Component } from 'react';
import './App.css';
import { observable, computed } from 'mobx';
import { observer,Provider,inject } from 'mobx-react'
//數(shù)據(jù)結(jié)構(gòu)
class Todo {
@observable todos = [
{
id: 1,
title: '任務(wù)1',
finished: false
}, {
id: 2,
title: '任務(wù)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>
未完成任務(wù)數(shù):{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('任務(wù)名字不能為空');
return;
}
todoList.todos.push({
id: 3, //臨時(shí)
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