2018-08-14 learning about work

begin:2018-08-13

step 1 熟悉react 写法

step 2 mobx 了解&使用

step 3 thrift接口调用过程

React&JavaScript

propsType

react可以在引入prop-types,配置propsTypes属性之后进行类型检查。

可以将属性声明为JS原生类型、React元素、某个类的实例,指定类型的对象等,也可以自定义,可以加上isRequired后缀,如果没有提供该信息,会打印警告。

还可以通过配置defaultProps,为props定义默认值。

props.childrenclass Grid extends React.Component {

constructor(props) {

super(props)

this.state = {}

}

render() {

return (

// 可以在这里控制子元素是否显示

{this.props.children}

// 只显示hello文本,并不显示子元素

//

hello

)

}

}

const Row = ({ name }) => {

return (

{name}

)

}

ReactDom.render(

,

document.getElementById('root')

)

es6 static methods

React & MobX

介绍&功能

mobx是一个状态管理器,下图是官网的原理图,看上去感觉跟Vue的双向数据绑定很相似。

通过action来修改组件状态,由于数据与视图双向绑定,一旦数据改变,会触发视图的更新,从而引起组件或者页面的重新渲染。

mobx的computed与vue的计算属性也有类似,都设置了缓存,依赖项没有发生变化的时候,该属性不会重新运行计算,只有在真正需要更新的时候才会更新。设置了computed的方法与普通方法的区别,也类似于vue的computed与method的区别。

感觉简单而言,从视图更新的过程来看,可以抽象成三个部分:action、state、views,mobx单项数据流,可以有下图的描述:

我觉得,State如果类比于MVVM的话,可以理解为ViewModel。

从开发者的角度来看:

本地搭建环境

本地需要搭建一个react-app环境并添加mobx等相关依赖。

step:create-react-app my-react-app 使用命令行工具创建新的react-app,并进入项目目录

(本地需先使用npm install -g create-react-app 命令安装工具)

安装babel等

npm install --save-dev babel-core babel-cli babel-preset-env babel-preset-react

创建&编写.babelrc文件

(这里的plugins如果不写也可以,关于支持ES7装饰器的配置问题,后面会再讲){

"presets": [

"env",

"react",

"stage-1",

"es2015"

],

"plugins": [

"transform-decorators-legacy",

"transform-decorators"

]

}

安装其他依赖,包括style-loader、babel-loader、css-loader等等。

这里我开始手动安装了webpack,然后安装webpack的时候,没有指定版本号,默认会安装最新版本Webpack4,运行时会报下面错误:

Cannot read property 'thisCompilation' of undefined during npm run build

参考这里的解决方式To solve this problem:Delete node_modules

Delete package-lock.json if present

If you have react-scripts in package.json, make sure you don't have webpack in it

Run yarn (or npm install)

Also make sure you don't have package.json or node_modules in the parent folders of your project

另一种方式是webpack降级到3。可以理解成webpack4与react-scripts不能同时在package.json中存在。

查找资料的时候发现,如果使用Create React App的话,其实是不需要手动再去安装Webpack的。

最后我删除了node_modules,然后package.json中删除了webpack,重新npm install或者yarn一下,问题解决了。

配置装饰器语法支持。

安装babel-plugin-transform-decorators、 babel-plugin-transform-decorators-legacy等相关依赖。

实际情况是,依赖装完,.babelrc文件中也配置了插件,webpack也配置完成之后,仍然无法识别装饰器语法,最后按照参考中的方法2解决了。但是这种方法需要在node_modules中修改,个人觉得不大好,暂时先这样处理下,后续再查看下。

通过npm run start启动项目,进行后续操作。

核心概念 & 使用

入门demo:import { observable } from 'mobx';

import { observer } from 'mobx-react';

import { Component } from 'react';

import React from "react";

import ReactDOM from "react-dom";

const appState = observable({

count: 0

})

// 这里不能写成剪头函数 否则数据绑定会失效

appState.increment = function () {

this.count++;

}

appState.decrement = function () {

this.count--;

}

@observer class Counter extends Component {

render() {

return (

Counter {this.props.store.count}

+

-

)

}

handleInc = () => {

this.props.store.increment()

}

handleDec = () => {

this.props.store.decrement()

}

}

const rootElement = document.getElementById("root");

ReactDOM.render(, rootElement);

Observable state(可观察的状态)

mobx使用ES7装饰器语法(可选使用)通过给现有属性增加@observable注解,就可以将属性设定为可观察的属性。使用装饰器属性可以使得书写代码更加简洁.

也可以写成这样class appState {

@observable count = 0;

increment = function () {

this.count++;

}

decrement = function () {

this.count--;

}

}

......

ReactDOM.render(, rootElement);

不过有个疑惑,下图方法1使用const定义是出于什么目的,官方文档的demo中也有很多是使用const定义的。

如果像下图方法二这样书写,是否有意义?count值也会改变,appState定义为const,其中内容是可以被改变的,如何控制不被改变?实际中是否会有这种情况?//1. 这里写成const是什么意义?

const appState = observable({

count: 0

})

//2. 这样写是否有意义?const?

const appState = {

@observable count: 0

}

Computed values

使用@computed 修饰getter方法,计算值延迟更新,只有依赖改变,需要重新计算的时候才会更新。

Reactions(反应)可以通过@observer将无状态组件变成响应式组件, MobX 会确保组件总是在需要的时重新渲染。

只要需要在状态发生改变时需要更新视图的view上使用@observer修饰,就可以实现自动更新。

自定义 reactions

Actions

actions执行状态的改变。

文档中有这么一段,个人觉得所有衍生同步更新,计算值延迟更新,这两句似乎有些矛盾,这里的所有衍生是否指的是reactions或者action后出发的事件?意思是说不能用计算值来改变状态,而是状态改变之后计算值一定已经变化?有点拗口。。。这里的同步更新和延迟更新到底指的是什么,感觉只能后面有时间看下源码才能了解了当状态改变时,所有衍生(任何 源自状态并且不会再有任何进一步的相互作用的东西就是衍生 )都会进行原子级的自动更新。因此永远不可能观察到中间值。

所有衍生默认都是同步更新。这意味着例如动作可以在改变状态之后直接可以安全地检查计算值。

计算值 是延迟更新的。任何不在使用状态的计算值将不会更新,直到需要它进行副作用(I / O)操作时。 如果视图不再使用,那么它会自动被垃圾回收。

所有的计算值都应该是纯净的。它们不应该用来改变状态。

其他注意

observable 相关通过 observable 传递对象时,后添加到对象的属性无法自动变成可观察的状态

这点有点类似于Vue中的对象数据绑定,如果在最开始定义的时候没有定义某个属性,后面再添加时将无法监控到这个属性的变化,可以使用vue.set来使得操作生效。当使对象转变成 observable 时,需要记住一些事情:当通过 observable 传递对象时,只有在把对象转变 observable 时存在的属性才会是可观察的。 稍后添加到对象的属性不会变为可观察的,除非使用 set 或 extendObservable。Array.isArray(observable([]))返回值为falseobservable.array 会创建一个人造数组(类数组对象)来代替真正的数组。 实际上,这些数组能像原生数组一样很好的工作,并且支持所有的原生方法,包括从索引的分配到包含数组长度。

请记住无论如何 Array.isArray(observable([])) 都将返回 false ,所以无论何时当你需要传递 observable 数组到外部库时,通过使用 array.slice()在 observable 数组传递给外部库或者内置方法前创建一份浅拷贝(无论如何这都是最佳实践)总会是一个好主意。 换句话说,Array.isArray(observable([]).slice()) 会返回 true。Array的sort&reverse方法会修改原数组,observableArray则不会不同于 sort 和 reverse 函数的内置实现,observableArray.sort 和 observableArray.reverse 不会改变数组本身,而只是返回一个排序过/反转过的拷贝。

computedcomputed&autorun并不一样。

二者都是响应式调用的衍生,但是computed可以理解为一个纯函数(即调用时刻的输出只由该时刻的输入决定,而不依赖于系统状态),如果使用过程中依赖没有被修改,则不会重新计算。autorun的使用场景更像是产生效果,例如对数据进行过滤操作(而不是产生数据),或者数据监控到数据变化之后的通知等副作用操作(这点与vue中的method并不一样,不要混淆)。如果你想响应式的产生一个可以被其它 observer 使用的值,请使用 @computed,如果你不想产生一个新值,而想要达到一个效果,请使用 autorun。 举例来说,效果是像打印日志、发起网络请求等这样命令式的副作用。

可以通过将computed作为一个函数,来获取在box中的计算值(即基本数据类型值)

错误处理如果计算值在其计算期间抛出异常,则此异常将捕获并在读取其值时重新抛出。 强烈建议始终抛出“错误”,以便保留原始堆栈跟踪。抛出异常不会中断跟踪,所有计算值可以从异常中恢复。const x = observable(3)

const y = observable(1)

const divided = computed(() => {

if (y.get() === 0)

throw new Error("Division by zero")

return x.get() / y.get()

})

divided.get() // 返回 3

y.set(0) // OK

divided.get() // 报错: Division by zero

divided.get() // 报错: Division by zero

y.set(2)

divided.get() // 已恢复; 返回 1.5

autorunautorun函数具有响应式功能,但是该函数不具有观察者。

autorun函数会立即触发,然后每次依赖关系发生改变时会再次触发。computed创建的函数,只有当它有自己的观察者时才会重新计算。

observer简单来说: 所有渲染 observable 数据的组件都需要使用@observer

在 reaction 中使用的特定 props 一定要间接引用(例如 const myProp = props.myProp)。不然,如果你在 reaction 中引用了 props.myProp,那么 props 的任何改变都会导致 reaction 的重新运行。

MobX 追踪属性访问,而不是值,可以理解为追踪的是引用,当引用的内存空间发生变化时触发响应行为,如果只是内存空间中的值发生变化,是不会被追踪的。

陷阱const message = observable({ title: "hello" })

autorun(() => {

// 错误

console.log(message)

// 正确

console.log(message.title)

})

// 不会触发重新运行

message.title = "Hello world"

其他解决方案:autorun(() => {

console.log(message.title) // 很显然, 使用了 `.title` observable

})

autorun(() => {

console.log(mobx.toJS(message)) // toJS 创建了深克隆,从而读取消息

})

autorun(() => {

console.log({...message}) // 创建了浅克隆,在此过程中也使用了 `.title`

})

autorun(() => {

console.log(JSON.stringify(message)) // 读取整个结构

})

action对于修改状态的函数使用@action

runInAction 是个简单的工具函数,它接收代码块并在(异步的)动作中执行。

仔细了解了异步Action这一部分,注意书写方式。

练习Demo

今天使用react+mobx 写了个todolist的demo,目前实现了添加和删除的功能。熟悉一下开发方式和书写方式。

主要代码:import React, { Component } from 'react'

import { observable, computed, observe, action } from 'mobx';

import ReactDOM from 'react-dom';

import { inject, Provider, observer } from 'mobx-react'

import './index.css';

import { debug } from 'util';

class Todo {

constructor(content) {

this.content = content

}

id = Math.random()

@observable content

@observable completed = false

}

class TodoListStore {

@observable todos = []

@computed get todosLength() {

return this.todos.length

}

@computed get completedLength() {

return this.todos.filter(item => item.completed).length

}

@computed get uncompletedLength() {

return this.todosLength - this.completedLength

}

@action

addTodo(todo) {

this.todos.push(todo)

}

@action

deleteTodo(index) {

this.todos.splice(index, 1)

// console.log(e)

}

}

// const TodoItem = observer(({ todo }) => (

//

//

// type="checkbox"

// checked={todo.completed}

// onClick={() => (todo.completed = !todo.completed)}

// />

// {todo.content}

// X

//

// ));

@observer

class TodoItem extends Component {

constructor(props) {

super(props)

}

render() {

const {todo, index} = this.props

return (

type="checkbox"

checked={todo.completed}

onClick={() => (todo.completed = !todo.completed)}

/>

{todo.content}

X

)

}

}

@observer

class TodoInput extends Component {

constructor(props) {

super(props)

this.state = new Todo()

}

addTodo() {

let content = this.refs.content.value

let item = new Todo(content)

this.props.store.addTodo(item)

console.log(this.props.store.todos)

this.refs.content.value = ''

}

render() {

return (

新增todo:

Add

)

}

}

@observer

class TodoList extends Component {

constructor(props) {

super(props)

this.state = {

todos: this.props.store.todos,

index: -1

}

}

delete(index) {

this.props.store.deleteTodo(index)

}

render() {

// let todos = [...this.props.store.todos]

return (

事项清单:

{this.state.todos.map((todo, index) => (

this.delete(index)}/>

)

)}

)

}

}

@observer

class TodoArchive extends Component {

render() {

let store = this.props.store

return (

总计:{store.todosLength}项

已完成:{store.completedLength}项

未完成:{store.uncompletedLength}项

)

}

}

class TodoListView extends Component {

render() {

let store = this.props.store

return (

)

}

}

let todolist = new TodoListStore()

ReactDOM.render(, document.getElementById('root'));查看原文

tenacity 报错_Tenacity相关推荐

  1. tenacity 报错_tenacity 重试

    tenacity 重试 简介 为了避免由于一些网络或等其他不可控因素,而引起的功能性问题.比如在发送请求时,会因为网络不稳定,往往会有请求超时的问题. 这种情况下,我们通常会在代码中加入重试的代码.重 ...

  2. tenacity 报错_关于Python错误重试方法总结

    前言 Tenacity是一个 Apache 2.0授权的通用重试库,用 Python 编写,用于简化向几乎所有内容添加重试行为的任务.它起源于一个重新尝试的分支,可惜这个分支已经不复存在了. 使用Te ...

  3. 继承WebMvcConfigurer 和 WebMvcConfigurerAdapter类依然CORS报错? springboot 两种方式稳定解决跨域问题

    继承WebMvcConfigurer 和 WebMvcConfigurerAdapter类依然CORS报错???springboot 两种方式稳定解决跨域问题! 之前我写了一篇文章,来解决CORS报错 ...

  4. Access to XMLHttpRequest at file from origin ‘null‘ has been blocked by CORS policy谷歌浏览器本地打开项目js文件报错

    Access to XMLHttpRequest at 'file:///xxxxx/PQ.BaseInfo.proto' from origin 'null' has been blocked by ...

  5. go build 编译报错 missing go.sum entry for module providing package

    go build 编译报错 missing go.sum entry for module providing package 解决方法 // 移除未使用的依赖 go mod tidy 再次编译,就可 ...

  6. docker报错:driver failed programming external connectivity on endpoint, iptables:No chain by that name

    docker 报错: Error response from daemon: Cannot restart container hello: driver failed programming ext ...

  7. mybatis查询报错:com.mysql.cj.exceptions.DataConversionException: Cannot determine value type from string

    mybatis查询报错: com.mysql.cj.exceptions.DataConversionException: Cannot determine value type from strin ...

  8. mongo报错:not authorized on bb to execute command { create: \“xxx\“...}

    mongo报错: {"ok" : 0,"errmsg" : "not authorized on bb to execute command { cr ...

  9. restTemplate http请求报错:no suitable HttpMessageConverter found for response type and content type

    报错信息: org.springframework.web.client.UnknownContentTypeException: Could not extract response: no sui ...

  10. 解决gitte提交报错 error: GE007: Your push would publish a private email address.

    错误情况: gitte提交报错,无法提交上去,报错如下: remote: Powered by GITEE.COM [GNK-6.0] remote: error: GE007: Your push ...

最新文章

  1. 通过cookies跳过验证码登陆页面,直接访问网站的其它URL
  2. .NET平台开源项目速览(8)Expression Evaluator表达式计算组件使用
  3. jQuery 追加元素的方法如append、prepend、before
  4. labview如何进行串口通讯(转)
  5. 【正一专栏】警察叔叔,我还是只是一个婴儿
  6. jpa 自定义sql if_mybatis仿jpa 使用@createDate @updateDate
  7. 从CLR GC到CoreCLR GC看.NET Core对云原生的支持
  8. 交换机选用要点及订货主要技术条件
  9. 进军SharePoint,资料先行....
  10. CSS 自定义滚动条样式
  11. 下载站mime属性设置(让文件可下载)
  12. Vue项目中国际化的语言切换
  13. 好看又实用的英文字体
  14. 透明质酸修饰牛血清蛋白|HA-BSA|荧光FITC标记透明质酸|FITC-peg-BSA
  15. 个人号微信SCRM客服系统功能介绍
  16. linux修复磁盘坏道
  17. win10开启热点后电脑无法打开网页
  18. STM32F7--->SDRAM
  19. 【DockerCE】Docker-CE 20.10.14正式版发布
  20. 10019---Linux查看CPU、内存、硬盘、版本信息

热门文章

  1. 叶俊:让能量爆棚的秘诀
  2. 行人重识别——评价标准
  3. keygen_Laravel随机密钥与Keygen
  4. 华为惠普入局挑战思科 中国企业网络市场混战
  5. 【论文简述】CVP-MVSNet:Cost Volume Pyramid Based Depth Inference for Multi-View Stereo(CVPR 2020)
  6. 搭建Hadoop高可用集群
  7. 8255芯片控制发光二极管模拟步进电机汇编实验
  8. WinForm实现Loading等待界面
  9. Elastic认证考试过程(2022.11.13 06:15)
  10. vs打包生成的文件有:setup.msi,setup.exe 二者区别