在學(xué)習(xí)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'
//數(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>
);
}
}
你會看到以下報錯信息:
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>
);
}
}
但還是報同樣的錯誤信息,這個頭大了呼巴,不知道怎么搞了氨淌。唯一的辦法就是冷靜下來,認(rèn)真思考
在好好思考后發(fā)現(xiàn)問題所在:injector
本身需要一個Provider
伊磺,我又把寫到inject
里面,這完全沒有用的删咱,看來是寫反了屑埋,應(yīng)該是一個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'
//數(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
,就沒有那么麻煩了峻黍,把多個store复隆,配到根上,子組件通過inject
自動注入姆涩。
以下為簡單應(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, //臨時
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;