如何在 React Native 应用程序中集成 Redux-Saga:初学者教程(第 2 部分)

言鼎科技 2023-07-04 497

我们在之前的教程中学习并实现了 redux-form 的基础知识:集成 Redux 表单(第 1 部分)。如果您对 Redux Form 没有基本的了解或者难以在您的应用程序中使用它,您可以访问该教程。现在,是时候加紧介绍 redux 形式的 redux-saga 了。您是否正在寻找一个简单的教程来开始在您的 React Native 应用程序中使用 Redux 中间件?如果是,那么您选择了正确的博客!

在本教程中,我们将使用redux-saga和 redux form在我们的演示应用程序中实现一个身份验证模块。

目标:简单的 Redux-Form 和 React-Saga 示例

在着手实施我们的身份验证模块之前,请观看下面的视频以更好地了解演示应用程序。

教程外卖

我们将主要了解-

  • Redux 传奇

  • Redux 形式

该演示将包含一个身份验证模块,我们在其中使用了 redux-form。该模块将有 -

  • 登记

  • 登录

  • 仪表板

使用两个redux-form特性:

  • Field Array – Field Array 组件用于呈现字段数组。

  • 向导表单——将单个表单分隔到不同输入页面的常见模式是向导。

并且还从登录和注册模块调用了 Firebase REST API。

因此,我们清楚要求和演示将包含的内容。不浪费更多时间,让我们开始构建我们的演示应用程序。

Redux 商店设置

第一步将是建立商店。
要将商店连接到您的应用程序,请打开 app/index.js

应用程序/index.js

从“商店”导入{商店}import { Provider as ReduxProvider } from 'react-redux'
导出默认值 () => (
  <ReduxProvider store={store}>
      <应用/>
  </ReduxProvider>)

所以,现在可以通过我们的整个应用程序访问商店。是时候在我们的应用程序中使用商店了。为此,我们需要做两件事——

  • 注册和登录页面的单独action.jssaga.js文件(我们将在接下来的部分中看到)

  • 一个名为store的文件夹包含三个文件——index.js、reducers.js 和 sagas.js

存储/索引。js

从'redux-saga'导入createSagaMiddleware;从'redux'导入{createStore,applyMiddleware};
从 './reducers' 导入 {combinedReducers};从 './sagas' 导入 rootSaga;
const sagaMiddleware = createSagaMiddleware();常量中间件 = [sagaMiddleware];
const store = createStore(combinedReducers, applyMiddleware(...middlewares));
sagaMiddleware.run(rootSaga);
出口{商店};

存储/reducers.js

从'redux'导入{combineReducers};从'redux-form'导入{reducer as formReducer};
export const combinedReducers = combineReducers({
形式:formReducer,
授权:AuthReducer,});

商店/sagas.js

从'redux-saga/effects'导入{all};从“screens/Login/saga”导入 loginScreenSaga;从“screens/Register/saga”导入 signupScreenSaga;函数* rootSaga() {
yield all([loginScreenSaga(), signupScreenSaga()]);}
导出默认的 rootSaga;

登记

我们会将注册表单分成单独的输入页面,命名为 -

  • 注册页面One.js

  • 注册PageTwo.js

  • RegisterPageThree.js

这种拆分模式称为向导形式。

注册/index.js

为了将表单分成小表单,我们将使用状态变量页面来跟踪要呈现的页面。

从“反应”中导入反应,{useState}从'react-native'导入{ScrollView}从 './RegisterPageOne' 导入 RegisterPageOne从 './RegisterPageTwo' 导入 RegisterPageTwo从 './RegisterPageThree' 导入 RegisterPageThree
const 注册 = (props) => {
   const [页面,设置页面] = useState(1)
   const onSubmit = (Values) => console.log(Values)
   常量 goToNextPage = () => setPage( page => page + 1 )
   常量 goToPrevPage = () => setPage( page => page - 1 )
   返回 (
      <滚动视图>
         {page === 1 && <RegisterPageOne nextPage={goToNextPage} />}
         {page === 2 && <RegisterPageTwo nextPage={goToNextPage} prevPage={goToPrevPage} />}
         {page === 3 && <RegisterPageThree onSubmit={onSubmit} prevPage={goToPrevPage} />}
      </滚动视图>
   )}
导出默认注册

注册/RegisterPageOne.js

RegisterPageOne 是我们的第一个组件,它将有两个字段:全名和用户名。

从“反应”导入反应从'react-native'导入{View}从 'redux-form' 导入 { Field, reduxForm }从“组件”导入 { FormInput , CustomButton }从 'utils/Validations' 导入 { usernameRequired , fullnameRequired }
const RegisterPageOne = ({handleSubmit,nextPage}) => {
   返回 (
       <视图>
           <字段
               名称=“全名”
               组件={FormInput}
               验证={[fullnameRequired]}
               placeholder="输入全名"  
           />
           <字段
               名称=“用户名”
               组件={FormInput}
               验证={[需要用户名]}
               placeholder="输入用户名"
               onSubmitEditing = {handleSubmit(nextPage)}
           />      
           <自定义按钮
               buttonLabel="下一步"
            onPress={handleSubmit(下一页)}
           />              
       </查看>
   )}
导出默认的 reduxForm({
   形式:'注册表格',
   destroyOnUnmount:假,
   forceUnregisterOnUnmount:真})(RegisterPageOne)

注册/RegisterPageTwo.js

RegisterPageTwo 是我们的第二个组件,具有三个字段:手机号码、电子邮件和兴趣爱好。爱好的输入使用 FieldArray API 向用户呈现多个输入。我们还将向输入字段添加验证。

从“反应”导入反应从 'react-native' 导入 { StyleSheet, View , Text }从 'redux-form' 导入 { Field, FieldArray, reduxForm }从“组件”导入 {DeleteButton、CustomButton、FormInput}从 'utils/Validations' 导入 { 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) => {
   常量错误 = {}

   if (!values.hobbies || !values.hobbies.length) errors.hobbies = { _error : “至少添加一个爱好” }
   别的{
       常数 hobbiesArrayErrors = []
       values.hobbies.forEach((爱好,索引)=>{
           如果 (!hobby || !hobby.length) hobbiesArrayErrors[index] = HOBBY_REQUIRED
       })
       如果(hobbiesArrayErrors.length)errors.hobbies = hobbiesArrayErrors
   }
   
   返回错误}
const RegisterPageTwo = ({prevPage,handleSubmit,nextPage}) => {
   返回 (
      <视图>
          <字段
              name="手机号"
              组件={FormInput}
              placeholder={“输入手机号码”}
              验证={[mobileNoRequired,validateMobileno]}
          />
          <字段
              名称=“电子邮件”
              组件={FormInput}
              占位符={“输入电子邮件”}
              验证={[emailRequired,validateEmail]}
          />
          <FieldArray name="hobbies" component={renderHobbies}/>
          <CustomButton buttonLabel={“Back”} onPress={prevPage}/>
          <自定义按钮
        buttonLabel={“下一步”}
        onPress={handleSubmit(下一页)}
      />                    
       </查看>
   )}
导出默认的 reduxForm({
   形式:'注册表格',
   证实,
   destroyOnUnmount :假,
   forceUnregisterOnUnmount : 真})(注册页面二)

注册/RegisterPageThree.js

RegisterPageThree 组件包括两个密码字段。添加了两个密码应匹配的验证。

从“反应”导入反应从'react-native'导入{View}从'react-redux'导入{connect}从 'redux-form' 导入 { Field, formValueSelector, reduxForm }从“组件”导入{CustomButton,FormInput}从 'utils/Validations' 导入 { passwordRequired, validatePassword }
让 RegisterPageThree = ({handleSubmit,onSubmit,prevPage}) => {

   const validateConfirmPassword = (密码) =>
       密码 && 密码 !== props.password
       ?验证_确认_密码
       : 不明确的

   返回 (
     <视图>
        <字段  
           名称=“密码”
           组件={FormInput}
           placeholder={“输入密码”}
           验证={[需要密码,验证密码]}
         />
         <字段
            名称=“确认密码”
            组件={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')导出默认 RegisterPageThree = connect(state => {
   const password = selector(state, '密码')
   返回 {密码}})(注册页面三)

注册/action.js

export const signupUser = user => ({
类型:'REGISTER_REQUEST',
有效载荷:用户,});

注册/saga.js

从'redux-saga/effects'导入{put,takeLatest};从“api/Signup”导入 {userSignup};
函数* signupUser({payload}) {
尝试 {
  const response = yield userSignup(payload);
  yield put({type: 'REGISTER_SUCCESS', response});
} 赶上(错误){
  yield put({type: 'REGISTER_FAILURE', error: error.message});
}}
导出默认函数* signupScreenSaga() {
yield takeLatest('REGISTER_REQUEST', signupUser);}

解释

  • 单击提交按钮时,将调用onSubmit ,并发送包含有效负载的signupUser(payload) 。

派遣(注册用户(有效载荷))
  • 从文件Register/action.js中,注册操作类型“REGISTER_REQUEST”将被调度。

  • 然后 saga 中间件将监视“REGISTER_REQUEST”类型的操作。

  • 它将获取该操作的最新遭遇并调用注册 API。

  • 对于成功的调用,它将发送带有响应数据的“REGISTER_SUCCESS”操作。

  • 对于 Fail 调用,它将发送带有错误消息的“REGISTER_FAILURE”操作。

更新减速器

打开store/reducers.js并添加这段代码说明 switch cases。

这个减速器服务于来自登录和注册的操作。这两个模块都派发相似类型的动作-

1. 请求动作:根据这个动作,reducer 将loading变量更新为 true。

2. Success Action:执行此操作后,reducer 将loading变量更新为 false,并将操作的响应存储到user变量。

3. 失败操作:在此操作后,reducer 将加载变量更新为 false 并将来自操作的响应存储到错误变量

另请阅读:

2022 年最佳 React Native 动画库和 UI 组件

存储/reducers.js

const AuthReducer = (state = initialState, action) => {
开关(动作类型){    
  案例“REGISTER_REQUEST”:
    返回 {
      ...状态,
      加载:真实,
    };

  案例“REGISTER_SUCCESS”:
    返回 {
      ...状态,
      用户:action.response,
      加载:错误,
    };

  案例“REGISTER_FAILURE”:
    返回 {
      ...状态,
      错误:action.error,
      加载:错误,
    };
   案例'LOGIN_REQUEST':
    返回 {
      ...状态,
      加载:真实,
    };

  案例“LOGIN_SUCCESS”:
    返回 {
      ...状态,
      用户:action.response,
      加载:错误,
    };

  案例“LOGIN_FAILURE”:
    返回 {
      ...状态,
      错误:action.error,
      加载:错误,
    };

  默认:
    返回状态;
}};

登录

登录页面接受两个输入 - 电子邮件和密码。

单击提交按钮时调用登录 API。成功登录后,将出现仪表板屏幕。

登录/index.js

从“反应”导入反应从 'redux-form' 导入 { Field, reduxForm }从'react-redux'导入{useDispatch}从 'react-native' 导入 {View, ScrollView}从 './actions' 导入 { loginUser }从“组件”导入{FormInput,CustomButton}import { passwordRequired, emailRequired, validatePassword , validateEmail } from 'utils/Validations'
const 登录 = (props) => {
   const dispatch = useDispatch()
   const onSubmit = (values) => dispatch(loginUser(values))
   返回 (
      <滚动视图>
         <字段
            名称=“电子邮件”
            组件={FormInput}
            占位符={“输入电子邮件”}
            验证={[emailRequired,validateEmail]}
          />
          <字段
             名称=“密码”
             组件={FormInput}
             placeholder={“输入密码”}
             验证={[需要密码,验证密码]}
           />
           <自定义按钮
              buttonLabel={“登录”}
              onPress={props.handleSubmit(onSubmit)}
            />
       </滚动视图>
   )}导出默认的 reduxForm({
   形式:'登录形式'})(登录)

登录/action.js

export const loginUser = (user) => ({
  输入:“LOGIN_REQUEST”,
  有效载荷:用户,});

登录/saga.js

从'redux-saga/effects'导入{put,takeLatest};从“api/登录”导入{userLogin};
函数* loginUser({payload}) {
尝试 {
  const response = yield userLogin(payload);
  yield put({type: 'LOGIN_SUCCESS', response});
} 赶上(错误){
  yield put({type: 'LOGIN_FAILURE', error: error.message});
}}导出默认函数* loginScreenSaga() {
yield takeLatest('LOGIN_REQUEST', loginUser);}

解释

  • 单击提交按钮时,将调用onSubmit ,并发送包含用户电子邮件和密码的loginUser(values) 。

const onSubmit = (values) => dispatch(loginUser(values))
  • 从文件Login/action.js中,将调度登录操作类型“LOGIN_REQUEST” 。

  • 然后 saga 中间件将监视“LOGIN_REQUEST”类型的操作。

  • 它将获取该操作的最新遭遇并调用登录 API。

  • 对于成功的调用,它将发送带有响应数据的“LOGIN_SUCCESS”操作。

  • 对于 Fail 调用,它将发送带有错误消息的“LOGIN_FAILURE”操作。

API调用

api/登录/index.js

const API_KEY = '' //把你的密钥放在这里常量端点= {
  登录:`https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=${API_KEY}`}
export const userLogin = async (user) => {
   const response = await fetch(endpoint.login,{
       方法:'POST',
       标题:{
           '内容类型':'应用程序/json'
       },
       正文:JSON.stringify({
           电子邮件:user.email,
           密码:用户.密码,
           返回安全令牌:真
       })
   })
   if(!response.ok) throw new Error('出事了!!');
   const responseData = await response.json()
   返回responseData.email}

仪表板

成功登录后,您将被重定向到仪表板页面。这是 UI 的代码。

仪表板/index.js

从“反应”导入反应;从'react-redux'导入{useSelector};从 'react-native-size-matters' 导入 {scale, verticalScale};从 'react-native' 导入 {Text, StyleSheet, SafeAreaView};
从“utils/Colors”导入颜色;
const 仪表板 = () => {
const userEmail = useSelector(state => state.Auth.user);

返回 (
  <SafeAreaView style={styles.screen}>
    <Text style={styles.hiText}>你好</Text>
    <Text style={styles.name}>{userEmail}</Text>
  </安全区域视图>
);};
导出默认仪表板;

useSelector()允许您使用选择器函数从 Redux 存储状态中提取数据,以便我们可以在我们的组件中使用它。如您所见,我们可以从state.Login.user中获取用户电子邮件地址的值。

您可以在Github Repository找到演示应用程序的完整源代码,您可以从中克隆和试用代码。

结论

所以,这是关于在 React Native 应用程序中使用 redux-form 实现 redux-saga。我们已经介绍了使用 redux-form 功能字段数组、向导表单和 redux-middleware 的完整身份验证。您可以访问React Native 教程页面以获取更多此类教程,并克隆 github 存储库进行实验。

如果您正在为您的 React Native 应用程序寻找帮助,请立即联系我们以聘请我们的React Native 开发人员。我们拥有经验丰富且技能娴熟的开发人员,他们拥有 React Native 的基础知识和高级知识。

言鼎科技

The End