您好,登錄后才能下訂單哦!
本系列文章學習和研究redux-form的主要參考資源,特別是代碼部分,主要在于其官方網站提供的一切資源及工程源碼剖析。
在使用 redux-form 之前,需要用戶具備以下基礎:
redux-form基于React-Redux狀態管理理念,而form本身作為一種「特殊」的容器組件,要實現這種組件與數據中心(即Redux的store)的交互,關鍵在于把握 redux-form 的三個主要模塊:
- formReducer reducer : 表單的各種操作以 Redux action 的方式,通過此 reducer 來促成 Redux store 數據的變化。
- reduxForm() API :此高階組件用以整合 Redux action 綁定的用戶交互與您的組件,并返回一個新的組件供以使用。
- <Field/> API: 用此代替您原生態的HTML5 <input/> 組件,可以與redux-form的邏輯相連接。
補充解釋如下。
有關代碼如下(store.js):
import { reducer as reduxFormReducer } from 'redux-form';
const rootReducer = combineReducers({
//other custom reducers
form: reduxFormReducer, // mounted under "form"
});
combineReducers工具函數組件各個子reducer,最后形成一個大型reducer,稱為rootReducer。然后,以此rootReducer為參數傳遞給createStore創建Redux的store對象。
Reducer的作用是:負責根據子組件發出的Action和原有State生成新的State,即:
Reducer的作用 |
---|
oldState+Action=>newState |
為了全面理解上面的代碼,讓我們再回顧一下Redux編程中Reducer拆分思想。Redux編程思想中建議把較大型的超過20行以上代碼的reducer函數拆成了若干個小型的recducer函數,每一個負責生成對應的一部分state。而且,這種拆分與 React 應用的結構相吻合:一個 React 根組件由很多子組件構成。這就是說,子組件與子 Reducer 完全可以一一對應。
Redux 提供的combineReducers方法,正是用于 Reducer 的拆分。你只要定義各個子 Reducer 函數,然后用這個方法,即可將它們合并成一個大的 Reducer。
典型情況下,上述combineReducers方法用場是:
生成rootReducer的模塊中。因為往往隨后使用rootReducer作為參數并通過調用createStore方法生成整個系統唯一的store,所以,combineReducers方法主要store.js模塊中。
關于combineReducers方法還有一個重要細節,請注意如下代碼:
const rootReducer = combineReducers({
chatLogReducer,
statusMessageReducer,
userNameReducer,
form: reduxFormReducer
});
這種寫法有一個前提: State 的屬性名必須與各個子 Reducer 同名;否則,就要采用下面的寫法。
const rootReducer = combineReducers({
chatLog:chatLogReducer,
statusMessage:statusMessageReducer,
userName:userNameReducer,
form: reduxFormReducer
});
因此,該函數根據 State 的 不同key 去執行相應的子 Reducer,并將返回結果合并成一個大的 State 對象。注意:最后一個form鍵名是不能更改的,這是redux-form系統規定的。
將來使用上面代碼的結果的方法是:
state.chatLog、state.statusMessage......
當然,由于一個典型的reducer是要返回一個新的狀態——一般使用對象方式表示;所以,最終你會見到代碼中出現類似于下面的引用形式:
state.chatLog.obj1.p1
這一點在redux-form官方網站提供的實例InitializeFromStateForm中文件InitializeFromStateForm.js中即有如下使用方式:
InitializeFromStateForm = connect(
state => ({
initialValues: state.accountReducer.data,
}),
{ load: loadAccount },
)(InitializeFromStateForm);
上面代碼行出現在示例表單定義模塊的代碼中,這里通過connect方法調用進一步包裝表單組件,實現把store中state有關數據(state.accountReducer.data)映射到表單組件的屬性上。
啰嗦上面這一些,就是為了強調一個簡短的combineReducers調用意義重大,正是這一調用最終把store數據(代碼中典型稱為state)與組件props關聯到一起。
API部分的描述是:reduxForm(config:Object)
這里,參數config是一個對象類型。此對象規定了系統內置的許多key,分別實現不同的功能。此高階組件方法用以整合 Redux action綁定的用戶交互與您的組件,并返回一個新的組件供以使用。
上面示例中的代碼用法如下:
InitializeFromStateForm = reduxForm({
form: 'initializeFromState', // a unique identifier for this form
})(InitializeFromStateForm);
InitializeFromStateForm = connect(
state => ({
initialValues: state.accountReducer.data, // pull initial values from account reducer
}),
{ load: loadAccount }, // bind account loading action creator
)(InitializeFromStateForm);
上面reduxForm方法調用至少有兩層含義:
(1)此方法進一步封裝上面定義的表單組件,從而實現組成表單的UI組件的屬性(props)(包括表單具體定義中的各個內置屬性與接下來通過connect創建的少數定制屬性,例如load)與store中的數據(即state,這個state中的對應形式可能是對象也可能是函數)關聯到一起。
(2)此方法返回一個新的表單組件,提供給index.js中ReactDOM.render方法最終渲染網頁中的表單使用,有關代碼如下:
ReactDOM.render(
<Provider store={store}>
<div style={{ padding: 15 }}>
<h3>Initialize From State</h3>
<InitializeFromStateForm onSubmit={showResults} />
<Values form="initializeFromState" />
</div>
</Provider>,
rootEl
);
所有需要與 store 數據連接的表單組件,都可以用 <Field/>。在正確使用它之前,需要清楚三條基本概念:
使用方法列舉如下:
可以是任何自定義的 class 組件(如下面的MyCustomInput組件),或者其他第三方庫。
/```
/ MyCustomInput.js
import React, { Component } from 'react'
class MyCustomInput extends Component {
render() {
const { input: { value, onChange } } = this.props
return (
<div>
<span>The current value is {value}.</span>
<button type="button" onClick={() => onChange(value + 1)}>Inc</button>
<button type="button" onClick={() => onChange(value - 1)}>Dec</button>
</div>
)
}
}
然后這樣使用:
import MyCustomInput from './MyCustomInput'
//...
<Field name="myField" component={MyCustomInput}/>
### 2.無狀態組件
這是一個非常靈活的使用 <Field/> 的方法。你必須在你的 render() 方法外定義它,否則它每次渲染都會被重建,并且由于組件的 prop 會變,就會強制 <Field/> 進行渲染。如果你在 render() 內部定義無狀態組件,不但會拖慢你的程序的運行,而且組件的input每次都會在組件重新渲染的時候失去焦點。
//在方法 render() 外定義
const renderField = (field) => (
<div className="input-row">
<input {...field.input} type="text"/>
{field.meta.touched && field.meta.error &&
<span className="error">{field.meta.error}</span>}
</div>
)
//在render()方法內定義
<Field name="myField" component={renderField}/>
### 3.最簡單且最常用的形式: input, select, or textarea
比如創建一個文字輸入框組件
<Field component="input" type="text"/>
# 參考
(1)https://github.com/tedyuen/react-redux-form-v6-example#field-value-lifecycle
(2)http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html
(3)https://redux-form.com/7.4.2/docs/gettingstarted.md/
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。