react imvc簡介


1. IMVC的I是Isomorphic的縮寫,意思是同構,指一份JS代碼既可以在Node.js運行也可以在Browser里運行
    1》M是Model,指狀態以及狀態變化的函數的集合,由initialState狀態和actions函數組成
    2》V是View的縮寫,React組件
    3》C是Controller的縮寫,指包含生命周期方法、事件處理器、同構工具方法及負責同步View和Model的中間媒介
    4》在react-imvc的Model中state是immutable data、action是pure function,View是React.js建議盡可能使用function stateless component寫法。所有跟外界的交互比如:Life-Cycle method、Ajax/Fetch、Event Handler時間處理器、localStorage等都放在Controller里。

 

2. Controller的一些重要屬性
    1》View是React Component組件,該組件的props結構如下:
          props.state是controller.store.getState()里的global state狀態樹
          props.handlers是controller實例里以handleXXX形式定義的事件處理器的集合對象
          props.actions是controller.store.actions里的actions集合對象
     2》Model屬性是一個對象,除了initialState屬性外其余都是pure function
     3》preload對象用來在頁面顯示前預加載css、json等數據
     4》handlers在初始化時從controller的實例里收集以handle開頭以箭頭函數形式定義的方法的集合對象,用來傳遞給controller.View組件

 

3. Controller的一些重要方法
     1》Event handler

import React from 'react'
import Controller from 'react-imvc/controller'

export default class extends Controller {
    View = View
    initialState = {
        count: 0,
    }
    actions = {
        INCREMENT: state => ({ ...state, count: state.count + 1 }),
        DECREMENT: state => ({ ...state, count: state.count - 1 }),
        CHANGE_BY_NUM: (state, num) => ({ ...state, count: state.count + Number(num) })
    }
    // 事件處理器必須使用 arrow function 箭頭函數的語法
    handleIncre = () => {
        let { INCREMENT } = this.store.actions
        INCREMENT()
    }
    // 事件處理器里使用 action 更新 global state
    handleDecre = () => {
        let { DECREMENT } = this.store.actions
        DECREMENT()
    }
    // 將特殊的索引如 index, id 或者其他信息,緩存在 DOM attribute 里
    // 在事件處理器里,從 DOM attribute 里取回
    handleCustomNum = event => {
        let { CHANGE_BY_NUM } = this.store.actions
        let num = event.currentTarget.getAttribute('data-num')
        CHANGE_BY_NUM(num)
    }
}

/**
* 在 view 組件里,可以從 props 里拿到 global state 和 global event handlers
*/
function View({ state, handlers }) {
    let { handleIncre, handleDecre, handleCustomNum } = handlers
    return (
        <div>
            <h1>Count: {state.count}</h1>
            <button onClick={handleIncre}>+1</button>
            <button onClick={handleDecre}>-1</button>
            <button onClick={handleCustomNum} data-num={10}>+10</button>
        </div>
    )
}

 

     2》handleInputChange(path, value, oldValue) -> final value
     3》Style組件將controller.preload里配置的css展示在頁面上

 

import React from 'react'
import Controller from 'react-imvc/controller'
import { Style } from 'react-imvc/component' // 加載 Style 組件

export default class extends Controller {
    preload = {
        'main': 'path/to/css' // 配置 css 文件路徑
    }
    View = View
}

// 當組件渲染時,Style 標簽會將 preload 里的同名 css 內容,展示為 style 標簽。
function View() {
    return (
        <div>
          <Style name="main" />
        </div>
    )
}

 

    4》Input組件用來將表單跟store聯系起來

 

import React from 'react'
import Controller from 'react-imvc/controller'
import { Input } from 'react-imvc/component' // 加載 Input 組件

export default class extends Controller {
    View = View
    // 可以在 Controller 里直接寫 initialState
    initialState = {
        // 多層次對象
        user: {
            name: {
                first: '',
                last: '',
            },
            email: '',
            age: 0
        },
        // 數組對象
        friends: [{
            name: 'friendA',
        }, {
            name: 'friendB',
        }],
        // 復合對象
        phone: {
            value: '',
            isValid: false,
            isWarn: false,
        },
        content: ''
    }
}

/**
* Input 組件支持 path 寫法,支持數組
* 可以用 .:/ 三種分隔符書寫 path
* 不需要寫 value,Input 組件會使用以下屬性:
* 1》使用 transformer 屬性可以在更新 store 之前做數據處理,接受兩個參數 transformer(newValue, oldValue),其返回值將作為最后更新到 store 的 value。
* 2》使用 check 屬性,可以驗證字段。當 Input 組件傳入了 check 屬性時,它將被視為復合對象 { value, isValid, isWarn } 三個屬性,它有以下行為:
*            - 當用戶 blur 脫離表單焦點時,使用 check 函數檢查 value 值,如果 check 函數返回 true,則 isValid = true,isWarn = false。
*            - 當用戶 focus 聚焦表單時,取消 isWarn = false 的狀態。
*            - 在將 input.value 更新到 store 時,會自動補全 `${name}.value` 更新 state。
* 3》使用 as 屬性,可以自定義渲染標簽.input 組件默認渲染為 input 標簽,可以使用 as 屬性將它渲染成 textarea 標簽或其他可以觸發 onChange 方法的組件。
*/
function View({ state }) {
    return (
        <div>
            firstname: <Input name="user.name.first" />
            lastname: <Input name="user:name:last" />
            email: <Input name="user/email" />
            age: <Input name="user.age" transformer={Number} >
            friends: {
                state.friends.map((friend, index) => {
                    return (
                        <div>
                            name: <Input name={`friends/${index}/name`} />
                        </div>
                    )
                })
            }
            phone: <Input name="phone" check={isValidPhone} />
            content: <Input as="textarea" name="content" />
        </div>
    )
}

 

3. Controller中重要的生命周期方法

    .》shouldComponentCreat()方法觸發時view還未被創建渲染,主要用於鑒定權限,如果用戶沒有權限訪問該頁面,可以通過 this.redirect 方法,重定向到其他頁面。
    .》componentWillCreate()方法觸發時view還未被創建渲染,可在方法內調用接口獲取首屏數據
    .》componentDidFirstMount() 方法觸發時用戶已經看到了首屏,可在方法內調用接口獲取非首屏數據。
    .》componentDidMount()方法觸發時component已經mount到頁面,可在方法內進行DOM操作等瀏覽器相關活動
    .》
componentWillUnmount()方法觸發時component即將從頁面unmount,解綁計時器等跟componentDidMount相關的逆操作
    .》stateDidChange(data)方法觸發時store里的state發生變化並且view也重新渲染,data中為actionType, actionPayload, previousState, currentState 

 

4. 高階組件connect(selector)(ReactComponent)
     connect是一個高階函數,第一次調用時接受selector函數作為參數返回withData函數。withData函數接受一個React組件作為參數返回一個新的React組件。withData會將selector函數返回的數據作為props傳入新的React組件。selector({state, handlers, actions})函數得到一個data參數包含三個字段,分別對應controller里的global state, global handlers和actions對象

 

import React from "react";
import connect from 'react-imvc/hoc/connect'

const withData = connect(({ state }) => {
  return {
    content: state.loadingText
  }
})

export default withData(Loading)

function Loading(props) {
  if (!props.content) {
    return null;
  }
  return (
    <div id="wxloading" className="wx_loading">
      <div className="wx_loading_inner">
        <i className="wx_loading_icon" />
        {props.content}
      </div>
    </div>
  );
}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM