【问题标题】:How to handle redux-saga and save user input data in Formik to Redux如何处理 redux-saga 并将 Formik 中的用户输入数据保存到 Redux
【发布时间】:2023-03-24 05:14:01
【问题描述】:

我正在制作非常简单的登录应用程序来学习 react 和 react-native,我的目标是获取用户输入,然后将这些值与包含用户和密码值的自定义假 api 文件进行比较,然后保存在 AsyncStorage (或localStorage)进行身份验证。所以我在互联网上搜索我要做什么,这是一个与我正在寻找的匹配的东西,但是我真的不明白这段代码是如何工作的。在这段代码中,有些事情让我困惑了一周,我脑子里有很多问题,所以我真的需要一些帮助。代码如下:

首先他的代码中有这样的 Redux Action

//Action.js
export const LoginRequested = (username,password) => {
  return {
    type: 'LOG_IN_REQUEST',
    data: {
      username,
      password,
    },
  };
};

export const LoginSuccessed = (data) => {
  return {
    type: 'LOGIN_SUCCESS',
    data,
  };
};

export const LoginFailed = (data) => {
  return {
    type: 'LOG_IN_FAILURE',
    data,
  };
};

export const Logout = (data) => {
  return {
    type: 'LOG_OUT',
    data
  };
};

但让我困惑的是

问题 1: 这里的data 是什么?这个data 是干什么用的?

我的意思是我可以理解在LoginRequested,数据是用户名和密码,所以我猜用户名和密码存储在这里,但在loginSuccessedLoginFailed,我不明白,这里的数据是什么

这里是减速器

const initialState = {
  isLoading: false,
  authen: false
};

export const loginReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'LOG_IN_REQUEST':
      {
        //console.log('action : LOG IN REQUEST');
        return {
          isLoading: true,
          authen: false
        }
      }
    case 'LOG_IN_SUCCESS':
      {
        //console.log('action : LOG IN SUCCESS');
        return {
          isLoading: false,
          authen: true
        };
      }
    case 'LOG_IN_FAILURE':
      {
        //console.log('action : LOG IN FAILURE');
        return initialState;
      }
    case 'LOG_OUT':
      {
        //console.log('action : LOG OUT');
        return initialState;
      }
    default:
      return state;
  }
};

对于reducer,所以:

问题 2: isLoadingauthen( maybe authentication) 是做什么的??

我可以理解它显示为登录状态,对吗?但我无法链接他如何使用那里的代码(我看到他在下面的传奇中使用过一次'LOGIN_SUCCESS',但我不明白)

这里是商店:

//store.js
const sagaMiddleware = createSagaMiddleware();
const store = createStore(rootReducer, applyMiddleware(sagaMiddleware)); //rootReducer is a combined reducer file, i don't show it here, but he have only one Reducer like above code
sagaMiddleware.run(rootSaga);

export default store;

这个我明白了,redux就是这样应用中间件的。

现在是佐贺部分

//saga.js
import { Alert } from 'react-native';
import { call, put, takeLatest } from 'redux-saga/effects';
//import axios from 'axios';
import { fetchLoginData } from '../../server/loginApi';

export function* loginMainSaga() {
  yield takeLatest('LOG_IN_REQUEST', loginSaga);
}

function* saveDataToStorage(data) {
  try {
      AsyncStorage.setItem(
          'userData',
          JSON.stringify({
              username: data.username,
              password: data.password }))  
      } catch(e) {
      console.log('error save to Storage');
  }
};

function* loginSaga(action) {
    const response = yield call(fetchLoginData);
    const resData = JSON.parse(JSON.stringify(response));
    
    const usernameAuth = String(resData.data[0].username);
    const passwordAuth = String(resData.data[0].password); 

    if (String(action.data.username) === usernameAuth)
    {
      if (String(action.data.password) === passwordAuth)
      {
        //console.log('loginSaga LOG_IN_SUCCESS');
        yield put({type: 'LOG_IN_SUCCESS'});
        saveDataToStorage(action.data);
      }
      else
      {
        const error = 'Password is incorrect'
        Alert.alert('Failed', error, [{ text: 'Ok', style: 'cancel' }] );
        //console.log('loginSaga LOG_IN_FAILURE');
        yield put({type: 'LOG_IN_FAILURE'});
      }
    } else {
      const error = 'Username is incorrect'
      Alert.alert('Failed', error, [{ text: 'Ok', style: 'cancel' }] );
      //console.log('loginSaga LOG_IN_FAILURE');
      yield put({type: 'LOG_IN_FAILURE'});
      
    }
}

我可以理解,loginMainSaga() 是获取最新的usernamepassword 存储在redux 中,并使用loginSaga 与Json 文件中的进行比较。 SaveDatatoStorage 表示您将用户名和密码保存到AsyncStorage

问题3:我上面的逻辑对吗?而loginSaga函数中的action这里是随机变量字还是直接指向action in redux reducer

而最令人困惑的部分是loginScreen:

他将代码拆分为不同的组件,只是Formik的基本样式和组件,详细here

这里是登录界面

function LoginScreen(props) {

    const dispatch = useDispatch();
    const loginHandler =({username, password}) => {
        dispatch(
            LoginRequested(username,password)
          );
      };

    const isLoading = useSelector(state => {
        //console.log('state.Login.isLoading ' + state.Login.isLoading);
        return state.Login.isLoading;
    });

    return(
        <Screen style={styles.container}>
            <MaterialCommunityIcons name="wechat" color="black" size={200} />
            <Text style={styles.title}>SIGN IN HERE</Text>

            <AppForm
                initialValues={{username: '', password: ''}}
                onSubmit={loginHandler}
                validationSchema={validateSchema}>
                <AppFormField
                    name="username"
                    placeholder="Username"
                    icon="account"
                    autoCapitalize="none"
                    autoCorrect={false}
                    textContentType="nickname"
                    width="75%"
                    ></AppFormField>
                <AppFormField
                    name="password"
                    placeholder="Password"
                    icon="lock"
                    autoCapitalize="none"
                    autoCorrect={false}
                    secureTextEntry
                    textContentType="password"
                    width="75%"></AppFormField>
                {isLoading ? 
                (
                <ActivityIndicator size="large" color={'black'} />
                ) : (
                <SubmitBtn title="Sign in" color={'black'} width="75%" />
                )}    
            </AppForm>

        <View style={styles.registerContainer}>
            <Text style={{color: 'black'}}>Don't have an account?</Text>
            <Text style={{color: 'black'}} onPress={() => null}> SIGN UP </Text>
            </View>
        </Screen>
    );
}

我不明白他怎么能得到userpassword, 我在这个文件中的第一个问题是:

问题4:为什么loginHandler const 在({username,password}) 中有{},为什么不使用(username,password)

而最让我头疼的是这周无法停止思考:

问题5:他如何在onSubmit时得到userpassword????他使用loginHandler,但是他如何添加usernamepassword,他如何捕获哪个输入是username,即password,如果我有3个表单输入,这怎么处理? formik onSubmit有什么特别之处吗????

这里是完整代码:FULL CODE

请帮助,您的帮助现在对我来说非常宝贵,也许可以解决像我这样的新人的问题。非常感谢你

【问题讨论】:

  • 请帮忙:((

标签: reactjs react-native react-redux react-hooks redux-saga


【解决方案1】:
  1. 第一组函数称为动作创建器。他们获取任何数据,并创建一个操作,将该数据与操作type 打包在一起。对于LoginRequested(),有效负载为usernamepassword。但是,并非所有操作都需要有有效负载,因此对于 Logout(),您可以从该操作创建者中排除任何参数。
  2. Reducer 采取由动作创建者(例如LoginRequestedlogout)产生的动作,并计算对存储状态的更新。从您提供的代码示例中,isLoadingauthen 是从某些操作中读取的两个布尔属性,并通过这些减速器存储在 redux 存储中。要了解这些值的来源,您需要调试创建这些类型的操作的位置:'LOG_IN_REQUEST'
  3. 您是正确的,动作有一个type 属性,它是任何随机标识符。使用类似短语的string 数据类型使其更具可读性是一种常见的做法。
  4. loginHandler 作为接受&lt;AppForm /&gt; onSubmit 的函数传递。任何基于 HTML 的表单的 onSubmit 都会在对象中传递一组键值对,因此 loginHandler 必须采用 {} 格式的参数
  5. 你是对的,因为onSubmit。此函数将获取其 HTML 节点中每个 HTML 输入元素的 name,并将其与相应元素的 value 配对。
                <AppFormField name="username" />
                <AppFormField name="password" />

【讨论】:

  • 现在我明白了,非常感谢您,先生,希望您有愉快的一天
  • 但是我仍然对问题1感到困惑,我的意思是,为什么他在这个登录表单中传递data,该数据代表什么,何时使用??
  • @LêQuốcKhánh 没问题,基于代码示例 data for LOG_OUT 未使用。因此,如果您完全删除 data,应用程序理论上应该可以完全一样地工作。 loginReducer 中的 case 是应该使用的地方,但不是。
  • 嘿先生,你能帮我用teamviewer什么的吗,当使用Formik自定义onHandleChange时,我无法输入任何东西
  • 问题太长了,我不能在这里显示:(((
猜你喜欢
  • 1970-01-01
  • 2019-06-14
  • 2017-05-21
  • 1970-01-01
  • 2017-05-28
  • 2020-05-08
  • 1970-01-01
  • 2019-03-03
  • 2018-09-08
相关资源
最近更新 更多