如何在 React Native 應(yīng)用程序中集成 Redux-Saga:初學(xué)者教程(第 2 部分)

言鼎科技 2023-07-04 498

我們在之前的教程中學(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.jssaga.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ò)誤變量

另請閱讀:

2022 年最佳 React Native 動(dòng)畫庫和 UI 組件

存儲(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í)。

言鼎科技

The End