摘要:安裝等相關(guān)依賴。通過啟動(dòng)項(xiàng)目,進(jìn)行后續(xù)操作。自定義執(zhí)行狀態(tài)的改變。任何不在使用狀態(tài)的計(jì)算值將不會(huì)更新,直到需要它進(jìn)行副作用操作時(shí)。強(qiáng)烈建議始終拋出錯(cuò)誤,以便保留原始堆棧跟蹤。
2018-08-14 learning about work
begin:2018-08-13
step 1 熟悉react 寫法
step 2 mobx 了解&使用
step 3 thrift接口調(diào)用過程
React&JavaScript propsTypepropsType官方文檔
react可以在引入prop-types,配置propsTypes屬性之后進(jìn)行類型檢查。
可以將屬性聲明為JS原生類型、React元素、某個(gè)類的實(shí)例,指定類型的對(duì)象等,也可以自定義,可以加上isRequired后綴,如果沒有提供該信息,會(huì)打印警告。
還可以通過配置defaultProps,為props定義默認(rèn)值。
props.childrenreact children
class Grid extends React.Component { constructor(props) { super(props) this.state = {} } render() { return ( // 可以在這里控制子元素是否顯示es6 static methods React & MobX 介紹&功能{this.props.children}// 只顯示hello文本,并不顯示子元素 //hello) } } const Row = ({ name }) => { return ({name}) } ReactDom.render(, document.getElementById("root") ) |
|
|
mobx是一個(gè)狀態(tài)管理器,下圖是官網(wǎng)的原理圖,看上去感覺跟Vue的雙向數(shù)據(jù)綁定很相似。
通過action來修改組件狀態(tài),由于數(shù)據(jù)與視圖雙向綁定,一旦數(shù)據(jù)改變,會(huì)觸發(fā)視圖的更新,從而引起組件或者頁面的重新渲染。
mobx的computed與vue的計(jì)算屬性也有類似,都設(shè)置了緩存,依賴項(xiàng)沒有發(fā)生變化的時(shí)候,該屬性不會(huì)重新運(yùn)行計(jì)算,只有在真正需要更新的時(shí)候才會(huì)更新。設(shè)置了computed的方法與普通方法的區(qū)別,也類似于vue的computed與method的區(qū)別。
感覺簡單而言,從視圖更新的過程來看,可以抽象成三個(gè)部分:action、state、views,mobx單項(xiàng)數(shù)據(jù)流,可以有下圖的描述:
我覺得,State如果類比于MVVM的話,可以理解為ViewModel。
從開發(fā)者的角度來看:
本地搭建環(huán)境本地需要搭建一個(gè)react-app環(huán)境并添加mobx等相關(guān)依賴。
step:
create-react-app my-react-app 使用命令行工具創(chuàng)建新的react-app,并進(jìn)入項(xiàng)目目錄
(本地需先使用npm install -g create-react-app 命令安裝工具)
安裝babel等
npm install --save-dev babel-core babel-cli babel-preset-env babel-preset-react
創(chuàng)建&編寫.babelrc文件
(這里的plugins如果不寫也可以,關(guān)于支持ES7裝飾器的配置問題,后面會(huì)再講)
{ "presets": [ "env", "react", "stage-1", "es2015" ], "plugins": [ "transform-decorators-legacy", "transform-decorators" ] }
安裝其他依賴,包括style-loader、babel-loader、css-loader等等。
這里我開始手動(dòng)安裝了webpack,然后安裝webpack的時(shí)候,沒有指定版本號(hào),默認(rèn)會(huì)安裝最新版本W(wǎng)ebpack4,運(yùn)行時(shí)會(huì)報(bào)下面錯(cuò)誤:
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降級(jí)到3。可以理解成webpack4與react-scripts不能同時(shí)在package.json中存在。
查找資料的時(shí)候發(fā)現(xiàn),如果使用Create React App的話,其實(shí)是不需要手動(dòng)再去安裝Webpack的。
最后我刪除了node_modules,然后package.json中刪除了webpack,重新npm install或者yarn一下,問題解決了。
配置裝飾器語法支持。
安裝babel-plugin-transform-decorators、 babel-plugin-transform-decorators-legacy等相關(guān)依賴。
實(shí)際情況是,依賴裝完,.babelrc文件中也配置了插件,webpack也配置完成之后,仍然無法識(shí)別裝飾器語法,最后按照參考中的方法2解決了。但是這種方法需要在node_modules中修改,個(gè)人覺得不大好,暫時(shí)先這樣處理下,后續(xù)再查看下。
通過npm run start啟動(dòng)項(xiàng)目,進(jìn)行后續(xù)操作。
核心概念 & 使用參考文檔
參考學(xué)習(xí)了 egghead.io課程
入門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 }) // 這里不能寫成剪頭函數(shù) 否則數(shù)據(jù)綁定會(huì)失效 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);
mobx使用ES7裝飾器語法(可選使用)通過給現(xiàn)有屬性增加@observable 注解,就可以將屬性設(shè)定為可觀察的屬性。使用裝飾器屬性可以使得書寫代碼更加簡潔.
也可以寫成這樣
class appState { @observable count = 0; increment = function () { this.count++; } decrement = function () { this.count--; } } ...... ReactDOM.render(, rootElement);
不過有個(gè)疑惑,下圖方法1使用const定義是出于什么目的,官方文檔的demo中也有很多是使用const定義的。
如果像下圖方法二這樣書寫,是否有意義?count值也會(huì)改變,appState定義為const,其中內(nèi)容是可以被改變的,如何控制不被改變?實(shí)際中是否會(huì)有這種情況?
//1. 這里寫成const是什么意義? const appState = observable({ count: 0 }) //2. 這樣寫是否有意義?const? const appState = { @observable count: 0 }
使用@computed 修飾getter方法,計(jì)算值延遲更新,只有依賴改變,需要重新計(jì)算的時(shí)候才會(huì)更新。
可以通過@observer將無狀態(tài)組件變成響應(yīng)式組件, MobX 會(huì)確保組件總是在需要的時(shí)重新渲染。
只要需要在狀態(tài)發(fā)生改變時(shí)需要更新視圖的view上使用@observer修飾,就可以實(shí)現(xiàn)自動(dòng)更新。
自定義 reactions
actions執(zhí)行狀態(tài)的改變。
文檔中有這么一段,個(gè)人覺得所有衍生同步更新,計(jì)算值延遲更新,這兩句似乎有些矛盾,這里的所有衍生是否指的是reactions或者action后出發(fā)的事件?意思是說不能用計(jì)算值來改變狀態(tài),而是狀態(tài)改變之后計(jì)算值一定已經(jīng)變化?有點(diǎn)拗口。。。這里的同步更新和延遲更新到底指的是什么,感覺只能后面有時(shí)間看下源碼才能了解了
當(dāng)狀態(tài)改變時(shí),所有衍生(任何 源自狀態(tài)并且不會(huì)再有任何進(jìn)一步的相互作用的東西就是衍生 )都會(huì)進(jìn)行原子級(jí)的自動(dòng)更新。因此永遠(yuǎn)不可能觀察到中間值。其他注意所有衍生默認(rèn)都是同步更新。這意味著例如動(dòng)作可以在改變狀態(tài)之后直接可以安全地檢查計(jì)算值。
計(jì)算值 是延遲更新的。任何不在使用狀態(tài)的計(jì)算值將不會(huì)更新,直到需要它進(jìn)行副作用(I / O)操作時(shí)。 如果視圖不再使用,那么它會(huì)自動(dòng)被垃圾回收。
所有的計(jì)算值都應(yīng)該是純凈的。它們不應(yīng)該用來改變狀態(tài)。
通過 observable 傳遞對(duì)象時(shí),后添加到對(duì)象的屬性無法自動(dòng)變成可觀察的狀態(tài)
這點(diǎn)有點(diǎn)類似于Vue中的對(duì)象數(shù)據(jù)綁定,如果在最開始定義的時(shí)候沒有定義某個(gè)屬性,后面再添加時(shí)將無法監(jiān)控到這個(gè)屬性的變化,可以使用vue.set來使得操作生效。
當(dāng)使對(duì)象轉(zhuǎn)變成 observable 時(shí),需要記住一些事情:
當(dāng)通過 observable 傳遞對(duì)象時(shí),只有在把對(duì)象轉(zhuǎn)變 observable 時(shí)存在的屬性才會(huì)是可觀察的。 稍后添加到對(duì)象的屬性不會(huì)變?yōu)榭捎^察的,除非使用 set 或 extendObservable。
Array.isArray(observable([]))返回值為false
observable.array 會(huì)創(chuàng)建一個(gè)人造數(shù)組(類數(shù)組對(duì)象)來代替真正的數(shù)組。 實(shí)際上,這些數(shù)組能像原生數(shù)組一樣很好的工作,并且支持所有的原生方法,包括從索引的分配到包含數(shù)組長度。請(qǐng)記住無論如何 Array.isArray(observable([])) 都將返回 false ,所以無論何時(shí)當(dāng)你需要傳遞 observable 數(shù)組到外部庫時(shí),通過使用 array.slice() 在 observable 數(shù)組傳遞給外部庫或者內(nèi)置方法前創(chuàng)建一份淺拷貝(無論如何這都是最佳實(shí)踐)總會(huì)是一個(gè)好主意。 換句話說,Array.isArray(observable([]).slice()) 會(huì)返回 true。
Array的sort&reverse方法會(huì)修改原數(shù)組,observableArray則不會(huì)
不同于?sort?和?reverse?函數(shù)的內(nèi)置實(shí)現(xiàn),observableArray.sort 和 observableArray.reverse 不會(huì)改變數(shù)組本身,而只是返回一個(gè)排序過/反轉(zhuǎn)過的拷貝。
computed&autorun并不一樣。
二者都是響應(yīng)式調(diào)用的衍生,但是computed可以理解為一個(gè)純函數(shù)(即調(diào)用時(shí)刻的輸出只由該時(shí)刻的輸入決定,而不依賴于系統(tǒng)狀態(tài)),如果使用過程中依賴沒有被修改,則不會(huì)重新計(jì)算。autorun的使用場(chǎng)景更像是產(chǎn)生效果,例如對(duì)數(shù)據(jù)進(jìn)行過濾操作(而不是產(chǎn)生數(shù)據(jù)),或者數(shù)據(jù)監(jiān)控到數(shù)據(jù)變化之后的通知等副作用操作(這點(diǎn)與vue中的method并不一樣,不要混淆)。
如果你想響應(yīng)式的產(chǎn)生一個(gè)可以被其它 observer 使用的值,請(qǐng)使用?@computed,如果你不想產(chǎn)生一個(gè)新值,而想要達(dá)到一個(gè)效果,請(qǐng)使用?autorun。 舉例來說,效果是像打印日志、發(fā)起網(wǎng)絡(luò)請(qǐng)求等這樣命令式的副作用。
可以通過將computed作為一個(gè)函數(shù),來獲取在box中的計(jì)算值(即基本數(shù)據(jù)類型值)
錯(cuò)誤處理
如果計(jì)算值在其計(jì)算期間拋出異常,則此異常將捕獲并在讀取其值時(shí)重新拋出。 強(qiáng)烈建議始終拋出“錯(cuò)誤”,以便保留原始堆棧跟蹤。拋出異常不會(huì)中斷跟蹤,所有計(jì)算值可以從異常中恢復(fù)。
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() // 報(bào)錯(cuò): Division by zero divided.get() // 報(bào)錯(cuò): Division by zero y.set(2) divided.get() // 已恢復(fù); 返回 1.5
autorun函數(shù)具有響應(yīng)式功能,但是該函數(shù)不具有觀察者。
autorun函數(shù)會(huì)立即觸發(fā),然后每次依賴關(guān)系發(fā)生改變時(shí)會(huì)再次觸發(fā)。computed創(chuàng)建的函數(shù),只有當(dāng)它有自己的觀察者時(shí)才會(huì)重新計(jì)算。
簡單來說:?所有渲染 observable 數(shù)據(jù)的組件都需要使用@observer
在 reaction 中使用的特定 props 一定要間接引用(例如?const myProp = props.myProp)。不然,如果你在 reaction 中引用了?props.myProp,那么 props 的任何改變都會(huì)導(dǎo)致 reaction 的重新運(yùn)行。
MobX 追蹤屬性訪問,而不是值,可以理解為追蹤的是引用,當(dāng)引用的內(nèi)存空間發(fā)生變化時(shí)觸發(fā)響應(yīng)行為,如果只是內(nèi)存空間中的值發(fā)生變化,是不會(huì)被追蹤的。
陷阱
const message = observable({ title: "hello" }) autorun(() => { // 錯(cuò)誤 console.log(message) // 正確 console.log(message.title) }) // 不會(huì)觸發(fā)重新運(yùn)行 message.title = "Hello world"
其他解決方案:
autorun(() => { console.log(message.title) // 很顯然, 使用了 `.title` observable }) autorun(() => { console.log(mobx.toJS(message)) // toJS 創(chuàng)建了深克隆,從而讀取消息 }) autorun(() => { console.log({...message}) // 創(chuàng)建了淺克隆,在此過程中也使用了 `.title` }) autorun(() => { console.log(JSON.stringify(message)) // 讀取整個(gè)結(jié)構(gòu) })
對(duì)于修改狀態(tài)的函數(shù)使用@action
runInAction?是個(gè)簡單的工具函數(shù),它接收代碼塊并在(異步的)動(dòng)作中執(zhí)行。
仔細(xì)了解了異步Action這一部分,注意書寫方式。
練習(xí)Demo今天使用react+mobx 寫了個(gè)todolist的demo,目前實(shí)現(xiàn)了添加和刪除的功能。熟悉一下開發(fā)方式和書寫方式。
地址
主要代碼:
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 }) => ( //
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/97385.html
摘要:是一個(gè)的簡單可擴(kuò)展的狀態(tài)管理庫。它的副作用是自動(dòng)更新。該函數(shù)返回一個(gè)值,當(dāng)返回值為的時(shí)候,才會(huì)繼續(xù)觸發(fā)第一個(gè)函數(shù)。當(dāng)返回值為時(shí),不再繼續(xù)監(jiān)聽。包含一個(gè),該值用來區(qū)分執(zhí)行事件的類型。 mobx 能干什么 使用 react 寫小型應(yīng)用,數(shù)據(jù)、業(yè)務(wù)邏輯和視圖的模塊劃分不是很細(xì)是沒有問題的。在這個(gè)階段,引入任何狀態(tài)管理庫,都算是奢侈的。但是隨著頁面邏輯的復(fù)雜度提升,在中大型應(yīng)用中,數(shù)據(jù)、業(yè)務(wù)邏...
摘要:環(huán)境搭建從零開始搭建開發(fā)環(huán)境引入安裝依賴新建修改引入并支持安裝依賴打包時(shí)將樣式模塊化,我們可以通過或引入樣式,并且相互不沖突。修改,引入創(chuàng)建使用語法報(bào)錯(cuò)修改引入狀態(tài)管理使用裝飾器語法修改修改源碼 環(huán)境搭建 1.從零開始搭建webpack+react開發(fā)環(huán)境 2.引入Typescript 安裝依賴 npm i -S @types/react @types/react-domnpm i -...
摘要:前言現(xiàn)在最熱門的前端框架,毫無疑問是。對(duì)于小型應(yīng)用,引入狀態(tài)管理庫是奢侈的。但對(duì)于復(fù)雜的中大型應(yīng)用,引入狀態(tài)管理庫是必要的。現(xiàn)在熱門的狀態(tài)管理解決方案,相繼進(jìn)入開發(fā)者的視野。獲得計(jì)算得到的新并返回。 前言 現(xiàn)在最熱門的前端框架,毫無疑問是React。 React是一個(gè)狀態(tài)機(jī),由開始的初始狀態(tài),通過與用戶的互動(dòng),導(dǎo)致狀態(tài)變化,從而重新渲染UI。 對(duì)于小型應(yīng)用,引入狀態(tài)管理庫是奢侈的。 但...
摘要:發(fā)現(xiàn)很有趣,所以我把這個(gè)項(xiàng)目用重構(gòu)了一次。舊的版本是用全家桶,就是構(gòu)建的在的的分支上。其次就是性能優(yōu)化的問題。就是無論如何,只要和發(fā)生了變化,就要發(fā)生一次。因?yàn)楹蛿?shù)據(jù)已經(jīng)解耦了。會(huì)檢測(cè)被觀察的數(shù)據(jù),只要數(shù)據(jù)發(fā)生改變,它就會(huì)去重新渲染。 背景 前一陣子,我剛寫了篇React全家桶實(shí)戰(zhàn),介紹了下我用react全家桶構(gòu)建一個(gè)react webapp的中遇到的一些問題。后來,我發(fā)現(xiàn)了mobx。...
摘要:官方推薦使用的情況是當(dāng)需要用到全局?jǐn)?shù)據(jù)的時(shí)候,比如主題,多語言制或者用戶登錄授權(quán)等等。 老鐵,學(xué)不動(dòng)了?不要慌,耽誤不了你幾分鐘...(說謊臉,汗) long long ago 使用react的同胞們,也許都苦惱過其狀態(tài)管理以及組件之間的數(shù)據(jù)傳遞和共享(笨重的方式通過props依次往子組件傳遞)。 這時(shí)候,redux(mobx類似)出現(xiàn)了,我們累死累活的從水深火熱中解放了(第三方的庫相...
閱讀 737·2021-11-11 16:54
閱讀 3052·2021-09-26 09:55
閱讀 2002·2021-09-07 10:20
閱讀 1198·2019-08-30 10:58
閱讀 1039·2019-08-28 18:04
閱讀 697·2019-08-26 13:57
閱讀 3581·2019-08-26 13:45
閱讀 1150·2019-08-26 11:42