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