如何处理 redux-saga 并将 Formik 中的用户输入数据保存到 Redux

How to handle redux-saga and save user input data in Formik to Redux

我正在制作非常简单的登录应用程序,用于学习 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
  };
};

但让我困惑的是

问题一: 这里的data是什么?这个data是做什么用的?

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

这里是 Reducer

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) 是做什么的?? .

我可以理解为登录状态,对吗?但我无法 link 他如何使用那里的代码(我看到他在下面的传奇中使用了一次 '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 部分

//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 中,并使用 [=27 与 Json 文件中的进行比较=]. SaveDatatoStorage 表示您将用户名和密码保存到 AsyncStorage.

问题三:我上面的逻辑对吗?而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,如果我有 3,他如何捕捉哪个输入是 username,即 password表单输入,如何处理? formik onSubmit有什么特别之处吗????

完整代码如下:FULL CODE

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

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