tenacity 报错_Tenacity
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 (
// 可以在这里控制子元素是否显示
// 只显示hello文本,并不显示子元素
//
)
}
}
const Row = ({ name }) => {
return (
)
}
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相关推荐
- tenacity 报错_tenacity 重试
tenacity 重试 简介 为了避免由于一些网络或等其他不可控因素,而引起的功能性问题.比如在发送请求时,会因为网络不稳定,往往会有请求超时的问题. 这种情况下,我们通常会在代码中加入重试的代码.重 ...
- tenacity 报错_关于Python错误重试方法总结
前言 Tenacity是一个 Apache 2.0授权的通用重试库,用 Python 编写,用于简化向几乎所有内容添加重试行为的任务.它起源于一个重新尝试的分支,可惜这个分支已经不复存在了. 使用Te ...
- 继承WebMvcConfigurer 和 WebMvcConfigurerAdapter类依然CORS报错? springboot 两种方式稳定解决跨域问题
继承WebMvcConfigurer 和 WebMvcConfigurerAdapter类依然CORS报错???springboot 两种方式稳定解决跨域问题! 之前我写了一篇文章,来解决CORS报错 ...
- 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 ...
- go build 编译报错 missing go.sum entry for module providing package
go build 编译报错 missing go.sum entry for module providing package 解决方法 // 移除未使用的依赖 go mod tidy 再次编译,就可 ...
- 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 ...
- mybatis查询报错:com.mysql.cj.exceptions.DataConversionException: Cannot determine value type from string
mybatis查询报错: com.mysql.cj.exceptions.DataConversionException: Cannot determine value type from strin ...
- mongo报错:not authorized on bb to execute command { create: \“xxx\“...}
mongo报错: {"ok" : 0,"errmsg" : "not authorized on bb to execute command { cr ...
- restTemplate http请求报错:no suitable HttpMessageConverter found for response type and content type
报错信息: org.springframework.web.client.UnknownContentTypeException: Could not extract response: no sui ...
- 解决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 ...
最新文章
- 通过cookies跳过验证码登陆页面,直接访问网站的其它URL
- .NET平台开源项目速览(8)Expression Evaluator表达式计算组件使用
- jQuery 追加元素的方法如append、prepend、before
- labview如何进行串口通讯(转)
- 【正一专栏】警察叔叔,我还是只是一个婴儿
- jpa 自定义sql if_mybatis仿jpa 使用@createDate @updateDate
- 从CLR GC到CoreCLR GC看.NET Core对云原生的支持
- 交换机选用要点及订货主要技术条件
- 进军SharePoint,资料先行....
- CSS 自定义滚动条样式
- 下载站mime属性设置(让文件可下载)
- Vue项目中国际化的语言切换
- 好看又实用的英文字体
- 透明质酸修饰牛血清蛋白|HA-BSA|荧光FITC标记透明质酸|FITC-peg-BSA
- 个人号微信SCRM客服系统功能介绍
- linux修复磁盘坏道
- win10开启热点后电脑无法打开网页
- STM32F7--->SDRAM
- 【DockerCE】Docker-CE 20.10.14正式版发布
- 10019---Linux查看CPU、内存、硬盘、版本信息
热门文章
- 叶俊:让能量爆棚的秘诀
- 行人重识别——评价标准
- keygen_Laravel随机密钥与Keygen
- 华为惠普入局挑战思科 中国企业网络市场混战
- 【论文简述】CVP-MVSNet:Cost Volume Pyramid Based Depth Inference for Multi-View Stereo(CVPR 2020)
- 搭建Hadoop高可用集群
- 8255芯片控制发光二极管模拟步进电机汇编实验
- WinForm实现Loading等待界面
- Elastic认证考试过程(2022.11.13 06:15)
- vs打包生成的文件有:setup.msi,setup.exe 二者区别