如何在 React Native 應(yīng)用程序中集成 Redux-Saga:初學(xué)者教程(第 2 部分)
我們在之前的教程中學(xué)習(xí)并實(shí)現(xiàn)了 redux-form 的基礎(chǔ)知識(shí):集成 Redux 表單(第 1 部分)。如果您對 Redux Form 沒有基本的了解或者難以在您的應(yīng)用程序中使用它,您可以訪問該教程。現(xiàn)在,是時(shí)候加緊介紹 redux 形式的 redux-saga 了。您是否正在尋找一個(gè)簡單的教程來開始在您的 React Native 應(yīng)用程序中使用 Redux 中間件?如果是,那么您選擇了正確的博客!
在本教程中,我們將使用redux-saga和 redux form在我們的演示應(yīng)用程序中實(shí)現(xiàn)一個(gè)身份驗(yàn)證模塊。
目標(biāo):簡單的 Redux-Form 和 React-Saga 示例
在著手實(shí)施我們的身份驗(yàn)證模塊之前,請觀看下面的視頻以更好地了解演示應(yīng)用程序。
教程外賣
我們將主要了解-
Redux 傳奇
Redux 形式
該演示將包含一個(gè)身份驗(yàn)證模塊,我們在其中使用了 redux-form。該模塊將有 -
登記
登錄
儀表板
使用兩個(gè)redux-form特性:
Field Array – Field Array 組件用于呈現(xiàn)字段數(shù)組。
向?qū)П韱巍獙蝹€(gè)表單分隔到不同輸入頁面的常見模式是向?qū)А?/span>
并且還從登錄和注冊模塊調(diào)用了 Firebase REST API。
因此,我們清楚要求和演示將包含的內(nèi)容。不浪費(fèi)更多時(shí)間,讓我們開始構(gòu)建我們的演示應(yīng)用程序。
Redux 商店設(shè)置
第一步將是建立商店。
要將商店連接到您的應(yīng)用程序,請打開 app/index.js
應(yīng)用程序/index.js
從“商店”導(dǎo)入{商店}import { Provider as ReduxProvider } from 'react-redux'
導(dǎo)出默認(rèn)值 () => (
<ReduxProvider store={store}>
<應(yīng)用/>
</ReduxProvider>)
所以,現(xiàn)在可以通過我們的整個(gè)應(yīng)用程序訪問商店。是時(shí)候在我們的應(yīng)用程序中使用商店了。為此,我們需要做兩件事——
注冊和登錄頁面的單獨(dú)action.js和saga.js文件(我們將在接下來的部分中看到)
一個(gè)名為store的文件夾包含三個(gè)文件——index.js、reducers.js 和 sagas.js
存儲(chǔ)/索引。js
從'redux-saga'導(dǎo)入createSagaMiddleware;從'redux'導(dǎo)入{createStore,applyMiddleware};
從 './reducers' 導(dǎo)入 {combinedReducers};從 './sagas' 導(dǎo)入 rootSaga;
const sagaMiddleware = createSagaMiddleware();常量中間件 = [sagaMiddleware];
const store = createStore(combinedReducers, applyMiddleware(...middlewares));
sagaMiddleware.run(rootSaga);
出口{商店};
存儲(chǔ)/reducers.js
從'redux'導(dǎo)入{combineReducers};從'redux-form'導(dǎo)入{reducer as formReducer};
export const combinedReducers = combineReducers({
形式:formReducer,
授權(quán):AuthReducer,});
商店/sagas.js
從'redux-saga/effects'導(dǎo)入{all};從“screens/Login/saga”導(dǎo)入 loginScreenSaga;從“screens/Register/saga”導(dǎo)入 signupScreenSaga;函數(shù)* rootSaga() {
yield all([loginScreenSaga(), signupScreenSaga()]);}
導(dǎo)出默認(rèn)的 rootSaga;
登記
我們會(huì)將注冊表單分成單獨(dú)的輸入頁面,命名為 -
注冊頁面One.js
注冊PageTwo.js
RegisterPageThree.js
這種拆分模式稱為向?qū)问健?/span>
注冊/index.js
為了將表單分成小表單,我們將使用狀態(tài)變量頁面來跟蹤要呈現(xiàn)的頁面。
從“反應(yīng)”中導(dǎo)入反應(yīng),{useState}從'react-native'導(dǎo)入{ScrollView}從 './RegisterPageOne' 導(dǎo)入 RegisterPageOne從 './RegisterPageTwo' 導(dǎo)入 RegisterPageTwo從 './RegisterPageThree' 導(dǎo)入 RegisterPageThree
const 注冊 = (props) => {
const [頁面,設(shè)置頁面] = useState(1)
const onSubmit = (Values) => console.log(Values)
常量 goToNextPage = () => setPage( page => page + 1 )
常量 goToPrevPage = () => setPage( page => page - 1 )
返回 (
<滾動(dòng)視圖>
{page === 1 && <RegisterPageOne nextPage={goToNextPage} />}
{page === 2 && <RegisterPageTwo nextPage={goToNextPage} prevPage={goToPrevPage} />}
{page === 3 && <RegisterPageThree onSubmit={onSubmit} prevPage={goToPrevPage} />}
</滾動(dòng)視圖>
)}
導(dǎo)出默認(rèn)注冊
注冊/RegisterPageOne.js
RegisterPageOne 是我們的第一個(gè)組件,它將有兩個(gè)字段:全名和用戶名。
從“反應(yīng)”導(dǎo)入反應(yīng)從'react-native'導(dǎo)入{View}從 'redux-form' 導(dǎo)入 { Field, reduxForm }從“組件”導(dǎo)入 { FormInput , CustomButton }從 'utils/Validations' 導(dǎo)入 { usernameRequired , fullnameRequired }
const RegisterPageOne = ({handleSubmit,nextPage}) => {
返回 (
<視圖>
<字段
名稱=“全名”
組件={FormInput}
驗(yàn)證={[fullnameRequired]}
placeholder="輸入全名"
/>
<字段
名稱=“用戶名”
組件={FormInput}
驗(yàn)證={[需要用戶名]}
placeholder="輸入用戶名"
onSubmitEditing = {handleSubmit(nextPage)}
/>
<自定義按鈕
buttonLabel="下一步"
onPress={handleSubmit(下一頁)}
/>
</查看>
)}
導(dǎo)出默認(rèn)的 reduxForm({
形式:'注冊表格',
destroyOnUnmount:假,
forceUnregisterOnUnmount:真})(RegisterPageOne)
注冊/RegisterPageTwo.js
RegisterPageTwo 是我們的第二個(gè)組件,具有三個(gè)字段:手機(jī)號(hào)碼、電子郵件和興趣愛好。愛好的輸入使用 FieldArray API 向用戶呈現(xiàn)多個(gè)輸入。我們還將向輸入字段添加驗(yàn)證。
從“反應(yīng)”導(dǎo)入反應(yīng)從 'react-native' 導(dǎo)入 { StyleSheet, View , Text }從 'redux-form' 導(dǎo)入 { Field, FieldArray, reduxForm }從“組件”導(dǎo)入 {DeleteButton、CustomButton、FormInput}從 'utils/Validations' 導(dǎo)入 { emailRequired, mobileNoRequired, validateEmail, validateMobileno }
const renderHobbies = ({ fields, meta : {error , submitFailed } }) => {
返回(
<視圖>
<自定義按鈕
buttonLabel={“添加愛好”}
onPress={() => fields.push({})}
/>
{fields.map((愛好,索引)=>(
<查看鍵={index}>
<字段
姓名={愛好}
placeholder={`愛好#${index + 1 }`}
組件={FormInput}
/>
<DeleteButton onDelete={() => fields.remove(index)} />
</查看>
))}
{ submitFailed && error && <Text>{error}</Text> }
</查看>
)}
const validate = (values,props) => {
常量錯(cuò)誤 = {}
if (!values.hobbies || !values.hobbies.length) errors.hobbies = { _error : “至少添加一個(gè)愛好” }
別的{
常數(shù) hobbiesArrayErrors = []
values.hobbies.forEach((愛好,索引)=>{
如果 (!hobby || !hobby.length) hobbiesArrayErrors[index] = HOBBY_REQUIRED
})
如果(hobbiesArrayErrors.length)errors.hobbies = hobbiesArrayErrors
}
返回錯(cuò)誤}
const RegisterPageTwo = ({prevPage,handleSubmit,nextPage}) => {
返回 (
<視圖>
<字段
name="手機(jī)號(hào)"
組件={FormInput}
placeholder={“輸入手機(jī)號(hào)碼”}
驗(yàn)證={[mobileNoRequired,validateMobileno]}
/>
<字段
名稱=“電子郵件”
組件={FormInput}
占位符={“輸入電子郵件”}
驗(yàn)證={[emailRequired,validateEmail]}
/>
<FieldArray name="hobbies" component={renderHobbies}/>
<CustomButton buttonLabel={“Back”} onPress={prevPage}/>
<自定義按鈕
buttonLabel={“下一步”}
onPress={handleSubmit(下一頁)}
/>
</查看>
)}
導(dǎo)出默認(rèn)的 reduxForm({
形式:'注冊表格',
證實(shí),
destroyOnUnmount :假,
forceUnregisterOnUnmount : 真})(注冊頁面二)
注冊/RegisterPageThree.js
RegisterPageThree 組件包括兩個(gè)密碼字段。添加了兩個(gè)密碼應(yīng)匹配的驗(yàn)證。
從“反應(yīng)”導(dǎo)入反應(yīng)從'react-native'導(dǎo)入{View}從'react-redux'導(dǎo)入{connect}從 'redux-form' 導(dǎo)入 { Field, formValueSelector, reduxForm }從“組件”導(dǎo)入{CustomButton,F(xiàn)ormInput}從 'utils/Validations' 導(dǎo)入 { passwordRequired, validatePassword }
讓 RegisterPageThree = ({handleSubmit,onSubmit,prevPage}) => {
const validateConfirmPassword = (密碼) =>
密碼 && 密碼 !== props.password
?驗(yàn)證_確認(rèn)_密碼
: 不明確的
返回 (
<視圖>
<字段
名稱=“密碼”
組件={FormInput}
placeholder={“輸入密碼”}
驗(yàn)證={[需要密碼,驗(yàn)證密碼]}
/>
<字段
名稱=“確認(rèn)密碼”
組件={FormInput}
placeholder={“重新輸入密碼”}
validate={[passwordRequired,validateConfirmPassword]}
/>
<CustomButton buttonLabel={“Back”} onPress={prevPage}/>
<CustomButton buttonLabel={“Next”} onPress={handleSubmit(nextPage)}/>
</查看>
)}
RegisterPageThree = reduxForm({
形式:'注冊表格',
destroyOnUnmount :假,
forceUnregisterOnUnmount : 真})(注冊頁面三)
const selector = formValueSelector('register-form')導(dǎo)出默認(rèn) RegisterPageThree = connect(state => {
const password = selector(state, '密碼')
返回 {密碼}})(注冊頁面三)
注冊/action.js
export const signupUser = user => ({
類型:'REGISTER_REQUEST',
有效載荷:用戶,});
注冊/saga.js
從'redux-saga/effects'導(dǎo)入{put,takeLatest};從“api/Signup”導(dǎo)入 {userSignup};
函數(shù)* signupUser({payload}) {
嘗試 {
const response = yield userSignup(payload);
yield put({type: 'REGISTER_SUCCESS', response});
} 趕上(錯(cuò)誤){
yield put({type: 'REGISTER_FAILURE', error: error.message});
}}
導(dǎo)出默認(rèn)函數(shù)* signupScreenSaga() {
yield takeLatest('REGISTER_REQUEST', signupUser);}
解釋
單擊提交按鈕時(shí),將調(diào)用onSubmit ,并發(fā)送包含有效負(fù)載的signupUser(payload) 。
派遣(注冊用戶(有效載荷))
從文件Register/action.js中,注冊操作類型“REGISTER_REQUEST”將被調(diào)度。
然后 saga 中間件將監(jiān)視“REGISTER_REQUEST”類型的操作。
它將獲取該操作的最新遭遇并調(diào)用注冊 API。
對于成功的調(diào)用,它將發(fā)送帶有響應(yīng)數(shù)據(jù)的“REGISTER_SUCCESS”操作。
對于 Fail 調(diào)用,它將發(fā)送帶有錯(cuò)誤消息的“REGISTER_FAILURE”操作。
更新減速器
打開store/reducers.js并添加這段代碼說明 switch cases。
這個(gè)減速器服務(wù)于來自登錄和注冊的操作。這兩個(gè)模塊都派發(fā)相似類型的動(dòng)作-
1. 請求動(dòng)作:根據(jù)這個(gè)動(dòng)作,reducer 將loading變量更新為 true。
2. Success Action:執(zhí)行此操作后,reducer 將loading變量更新為 false,并將操作的響應(yīng)存儲(chǔ)到user變量。
3. 失敗操作:在此操作后,reducer 將加載變量更新為 false 并將來自操作的響應(yīng)存儲(chǔ)到錯(cuò)誤變量
存儲(chǔ)/reducers.js
const AuthReducer = (state = initialState, action) => {
開關(guān)(動(dòng)作類型){
案例“REGISTER_REQUEST”:
返回 {
...狀態(tài),
加載:真實(shí),
};
案例“REGISTER_SUCCESS”:
返回 {
...狀態(tài),
用戶:action.response,
加載:錯(cuò)誤,
};
案例“REGISTER_FAILURE”:
返回 {
...狀態(tài),
錯(cuò)誤:action.error,
加載:錯(cuò)誤,
};
案例'LOGIN_REQUEST':
返回 {
...狀態(tài),
加載:真實(shí),
};
案例“LOGIN_SUCCESS”:
返回 {
...狀態(tài),
用戶:action.response,
加載:錯(cuò)誤,
};
案例“LOGIN_FAILURE”:
返回 {
...狀態(tài),
錯(cuò)誤:action.error,
加載:錯(cuò)誤,
};
默認(rèn):
返回狀態(tài);
}};
登錄
登錄頁面接受兩個(gè)輸入 - 電子郵件和密碼。
單擊提交按鈕時(shí)調(diào)用登錄 API。成功登錄后,將出現(xiàn)儀表板屏幕。
登錄/index.js
從“反應(yīng)”導(dǎo)入反應(yīng)從 'redux-form' 導(dǎo)入 { Field, reduxForm }從'react-redux'導(dǎo)入{useDispatch}從 'react-native' 導(dǎo)入 {View, ScrollView}從 './actions' 導(dǎo)入 { loginUser }從“組件”導(dǎo)入{FormInput,CustomButton}import { passwordRequired, emailRequired, validatePassword , validateEmail } from 'utils/Validations'
const 登錄 = (props) => {
const dispatch = useDispatch()
const onSubmit = (values) => dispatch(loginUser(values))
返回 (
<滾動(dòng)視圖>
<字段
名稱=“電子郵件”
組件={FormInput}
占位符={“輸入電子郵件”}
驗(yàn)證={[emailRequired,validateEmail]}
/>
<字段
名稱=“密碼”
組件={FormInput}
placeholder={“輸入密碼”}
驗(yàn)證={[需要密碼,驗(yàn)證密碼]}
/>
<自定義按鈕
buttonLabel={“登錄”}
onPress={props.handleSubmit(onSubmit)}
/>
</滾動(dòng)視圖>
)}導(dǎo)出默認(rèn)的 reduxForm({
形式:'登錄形式'})(登錄)
登錄/action.js
export const loginUser = (user) => ({
輸入:“LOGIN_REQUEST”,
有效載荷:用戶,});
登錄/saga.js
從'redux-saga/effects'導(dǎo)入{put,takeLatest};從“api/登錄”導(dǎo)入{userLogin};
函數(shù)* loginUser({payload}) {
嘗試 {
const response = yield userLogin(payload);
yield put({type: 'LOGIN_SUCCESS', response});
} 趕上(錯(cuò)誤){
yield put({type: 'LOGIN_FAILURE', error: error.message});
}}導(dǎo)出默認(rèn)函數(shù)* loginScreenSaga() {
yield takeLatest('LOGIN_REQUEST', loginUser);}
解釋
單擊提交按鈕時(shí),將調(diào)用onSubmit ,并發(fā)送包含用戶電子郵件和密碼的loginUser(values) 。
const onSubmit = (values) => dispatch(loginUser(values))
從文件Login/action.js中,將調(diào)度登錄操作類型“LOGIN_REQUEST” 。
然后 saga 中間件將監(jiān)視“LOGIN_REQUEST”類型的操作。
它將獲取該操作的最新遭遇并調(diào)用登錄 API。
對于成功的調(diào)用,它將發(fā)送帶有響應(yīng)數(shù)據(jù)的“LOGIN_SUCCESS”操作。
對于 Fail 調(diào)用,它將發(fā)送帶有錯(cuò)誤消息的“LOGIN_FAILURE”操作。
API調(diào)用
api/登錄/index.js
const API_KEY = '' //把你的密鑰放在這里常量端點(diǎn)= {
登錄:`https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${API_KEY}`}
export const userLogin = async (user) => {
const response = await fetch(endpoint.login,{
方法:'POST',
標(biāo)題:{
'內(nèi)容類型':'應(yīng)用程序/json'
},
正文:JSON.stringify({
電子郵件:user.email,
密碼:用戶.密碼,
返回安全令牌:真
})
})
if(!response.ok) throw new Error('出事了!!');
const responseData = await response.json()
返回responseData.email}
儀表板
成功登錄后,您將被重定向到儀表板頁面。這是 UI 的代碼。
儀表板/index.js
從“反應(yīng)”導(dǎo)入反應(yīng);從'react-redux'導(dǎo)入{useSelector};從 'react-native-size-matters' 導(dǎo)入 {scale, verticalScale};從 'react-native' 導(dǎo)入 {Text, StyleSheet, SafeAreaView};
從“utils/Colors”導(dǎo)入顏色;
const 儀表板 = () => {
const userEmail = useSelector(state => state.Auth.user);
返回 (
<SafeAreaView style={styles.screen}>
<Text style={styles.hiText}>你好</Text>
<Text style={styles.name}>{userEmail}</Text>
</安全區(qū)域視圖>
);};
導(dǎo)出默認(rèn)儀表板;
useSelector()允許您使用選擇器函數(shù)從 Redux 存儲(chǔ)狀態(tài)中提取數(shù)據(jù),以便我們可以在我們的組件中使用它。如您所見,我們可以從state.Login.user中獲取用戶電子郵件地址的值。
您可以在Github Repository找到演示應(yīng)用程序的完整源代碼,您可以從中克隆和試用代碼。
結(jié)論
所以,這是關(guān)于在 React Native 應(yīng)用程序中使用 redux-form 實(shí)現(xiàn) redux-saga。我們已經(jīng)介紹了使用 redux-form 功能字段數(shù)組、向?qū)П韱魏?redux-middleware 的完整身份驗(yàn)證。您可以訪問React Native 教程頁面以獲取更多此類教程,并克隆 github 存儲(chǔ)庫進(jìn)行實(shí)驗(yàn)。
如果您正在為您的 React Native 應(yīng)用程序?qū)ふ規(guī)椭埩⒓绰?lián)系我們以聘請我們的React Native 開發(fā)人員。我們擁有經(jīng)驗(yàn)豐富且技能嫻熟的開發(fā)人員,他們擁有 React Native 的基礎(chǔ)知識(shí)和高級知識(shí)。