React.js学习笔记(17)|React.js学习笔记(17) Mobx

(1) Decorator 装饰器 Decorator是一个函数,用来修改类或者类的属性的行为。
说的直白点decorator就是给类添加或者修改类的变量与方法的。

  • ES7 中的 decorator 是个语法糖,不过依赖于 ES5 的Object.defineProperty 方法 。
(1) Object.defineProperty
  • defineProperty 所做的事情就是,为一个对象增加新的属性,或者更改对象某个已存在的属性。
  • 调用方式是 Object.defineProperty(obj, prop, descriptor),这 3 个参数分别代表:
    obj: 目标对象
    prop: 属性名
    descriptor: 针对该属性的描述符
    有意思的是 descriptor 参数,它其实也是一个对象,其字段决定了 obj 的prop 属性的一些特性。比如 enumerable 的真假就能决定目标对象是否可枚举(能够在 for…in 循环中遍历到,或者出现在 Object.keys 方法的返回值中),writable 决定目标对象的属性是否可以更改,等等。
(2) Decorator 例子:
(1) class Dog { bark () { return 'wang!wang!' } }-------------------------------------------------如果我们想让 bark 这个方法成为一个只读的属性,那么可以定义一个readonly 的 decorator:(2) // 注意这里的 `target` 是 `Dog.prototype` function readonly(target, key, descriptor) { descriptor.writable = false return descriptor }可以看到,decorator 就是一个普通函数,只不过它接收 3 个参数,与Object.defineProperty 一致。具体在这里,我们就是把 descriptor 的writable 字段设为 false。然后把 readonly 作用到 bark 方法上:(3) class Dog { @readonly bark () { return 'wang!wang!' } }let dog = new Dog() dog.bark = 'bark!bark!' // Cannot assign to read only property 'bark' of [object Object]总结:ES7 的 decorator,作用就是返回一个新的 descriptor,并把这个新返回的 descriptor 应用到目标方法上。

https://zhuanlan.zhihu.com/FrontendMagazine/20139834 (2) Mobx (1) observable 被观察者 作用:存储状态(Store state),可以是任何的数据结构,observable可以用来观测一个数据,这个数据可以数字、字符串、数组、对象等类型
  • 用法:observable(value) 或者 @observable classProperty = value
@observable classProperty = value---------------------------------------------// 这里引入的是 mobx import {observable} from 'mobx'; class Store { @observable todos = [{ title: "todo标题", done: false, }]; }

(2) observer 观察者 使用 @observer ,将组件变为观察者,响应 todos 状态变化。
当状态变化时,组件也会做相应的更新。
// 这里引入的是 mobx-react import {observer} from 'mobx-react'; @observer class TodoBox extends Component{ render() { return (
    {this.props.store.todos.map(todo =>
  • {todo.title}
  • )}
) } }

(3) action
首先在 Store 中,定义一个 action。class Store { @observable todos = [{ title: "todo标题", done: false, }]; @action changeTodoTitle({index,title}){ this.todos[index].title = title } }----------------------------------------------------------------在 Component 中调用,这样通过 action 的方法,就避免了直接修改 props 的问题。 { this.props.store.changeTodoTitle({index:0,title:"修改后的todo标题"}); }} value="https://www.it610.com/article/点我"/>'严格模式: 可以通过引入 mobx 定义的严格模式,强制使用 action 来修改状态。import {useStrict} from 'mobx'; useStrict(true);

(4) computed 计算属性
import {observable, computed} from "mobx"; class OrderLine { @observable price = 0; @observable amount = 1; constructor(price) { this.price = price; }@computed get total() { return this.price * this.amount; } }

(5) autorun
var numbers = observable([1,2,3]); var sum = computed(() => numbers.reduce((a, b) => a + b, 0)); var disposer = autorun(() => console.log(sum.get())); // 输出 '6' numbers.push(4); // 输出 '10'disposer(); numbers.push(5); // 不会再输出任何值。`sum` 不会再重新计算。

(6) mobx在react中的使用流程:
  • 安装mobx
  • 安装mobx-react
  • 安装babel-preset-stage-1 插件
  • 安装transform-decorators-legacy 插件
    transform-decorators-legacy是目前babel插件转换decorator的
安装: cnpm install mobx --sava cnpm install mobx-react -S// --save的简写形式 cnpm install babel-plugin-transform-decorators-legacy --save-dev cnpm install babel-preset-stage-1 -D//--save-dev的简写形式---------------------------------------------------使用: .babelrc文件{ "presets":[ ["es2015", {"loose": true}], "stage-1",//省事就安装"stage-0",因为它包含stage-1, stage-2以及stage-3的所有功能 "react" ], "plugins": ["transform-decorators-legacy","react-hot-loader/babel"] }注意: transform-decorators-legacy 一定要写在最前面

  • 声明store 定义state
store文件中的 app-state.js 文件import{observable, computed, autorun, action} from 'mobx'; export class AppState { @observable count = 0; // 被观察的变量 @observable name = 'woow'; @computed get msg() {// 计算属性 return `${this.name} say count is ${this.count}` }; @action add() { this.count += 1; } }const appState = new AppState(); // 实例化autorun(() => { console.log(appState.msg)// 注意:computed调用的时候是属性,不是方法 })// 比如: console.log(appState.msg())就会报错,计算属性!!setInterval(()=>{ appState.add(); // 调用add() action },1000)export default appState;

  • 把store连接到应用上
import React from 'react'; import ReactDom from 'react-dom'; import App from './view/App.jsx'; import {AppContainer} from 'react-hot-loader'; import {BrowserRouter} from 'react-router-dom'; import {Provider} from 'mobx-react'; // 引入Provider,储存store给子组件,和react-redux一样的 import appStateA from './store/app-state.js'; // 引入app-state.js中export default的内容const root = document.getElementById('root'); const render = Component => { ReactDom.hydrate( // react-hot-loader规定必须放在最外层// Provider储存store中的数据,给子组件使用 , root ) }render(App)if(module.hot) { module.hot.accept('./view/App.jsx', ()=> { const NextApp = require('./view/App.jsx').default; render(NextApp) }) }

  • 子组件 得到数据
import React,{Component} from 'react'; import {observer, inject} from 'mobx-react'// inject是注入的意思 import PropTypes from 'prop-types'; import {AppState} from '../../store/app-state.js'; @inject('appState') @observer// 在Provider上定义的属性 export default class TopicList extends Component { static propTypes = { appState: PropTypes.instanceOf(AppState).isRequired } changeName = (e) => { this.props.appState.name = e.target.value } render() { return (topic-list // this.changeName(e)} />这样也行{this.props.appState.msg}) } }--------------------------------------------------------------------以上改变name的方法不推荐,以为不好统一管理:一般都要在store中定义好@action 让后调用即可例如: 在store文件中的app-state.js文件中import{observable, computed, autorun, action} from 'mobx'; export class AppState { @observable count = 0; @observable name = 'woow'; @computed get msg() { return `${this.name} say count is ${this.count}` }; @action add() { this.count += 1; } @action chageName(name) {// 定义好改变name的action this.name = name; } }const appState = new AppState(); autorun(() => { console.log(appState.msg) })setInterval(()=>{ appState.add(); },1000)export default appState; ------------------------------------------------------------------在子组件中调用:import React,{Component} from 'react'; import {observer, inject} from 'mobx-react' import PropTypes from 'prop-types'; import {AppState} from '../../store/app-state.js'; @inject('appState') @observer export default class TopicList extends Component { static propTypes = { appState: PropTypes.instanceOf(AppState).isRequired } changeName = (e) => { this.props.appState.name = e.target.value } changeName2 = (e) => {// 这样方式才正确合理 this.props.appState.chageName(e.target.value) } render() { return (topic-list this.changeName(e)} />// 这种方式才正确合理{this.props.appState.msg}) } }

http://blog.csdn.net/u012125579/article/details/69400169 其他 ps: vscode编辑器使用mobx中 修饰器 相关语法报错:
配置: "javascript.implicitProjectConfig.experimentalDecorators": true,
【React.js学习笔记(17)|React.js学习笔记(17) Mobx】router
  • exact
import React from 'react'; import TopicLsit from '../views/top-list/index.jsx'; import TopicDetail from '../views/topic-detail/index.jsx'; import {Route} from 'react-router-dom'; export default () => [ , ]输入路由‘/detail’,会匹配‘/’,‘/list’两个,所以加上exact="true",就只会匹配‘/detail’,不再匹配‘/’例如: export default () => [ , ] 输入路由‘/detail’就只会匹配‘/detail’,而不会再匹配上‘/’简写形式: :,

  • Redirect 重定向
export default () => [ } exact={true}/>, , ] ‘/’路由重定向到‘/detail’---------------------------------------------------注意:Redirect可以写成下面这样,这种情况一般都要配合Switch标签

    推荐阅读