You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中按钮 onPress 触发Redux Action的实现咨询

Hey there! Let's break down exactly how to make your login button trigger a Redux action, handle the API call with Redux Saga, and react once you get that auth_token. I'll walk you through each step with code examples you can adapt to your project.


Step 1: Define Redux Actions & Reducer

First, we need to set up the action types and creators that will kick off the login flow, plus a reducer to manage your auth state (loading status, token, and errors).

Action Types & Creators

// actions/authActions.js
export const FETCH_DATA = 'FETCH_DATA';
export const FETCH_DATA_SUCCESS = 'FETCH_DATA_SUCCESS';
export const FETCH_DATA_FAILURE = 'FETCH_DATA_FAILURE';

// Trigger login API request
export const fetchData = (username, password) => ({
  type: FETCH_DATA,
  payload: { username, password }
});

// Dispatch on successful authentication
export const fetchDataSuccess = (authToken) => ({
  type: FETCH_DATA_SUCCESS,
  payload: authToken
});

// Dispatch on API failure
export const fetchDataFailure = (error) => ({
  type: FETCH_DATA_FAILURE,
  payload: error
});

Auth Reducer

// reducers/authReducer.js
import { FETCH_DATA, FETCH_DATA_SUCCESS, FETCH_DATA_FAILURE } from '../actions/authActions';

const initialState = {
  loading: false,
  authToken: null,
  error: null
};

const authReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_DATA:
      return {
        ...state,
        loading: true,
        error: null
      };
    case FETCH_DATA_SUCCESS:
      return {
        ...state,
        loading: false,
        authToken: action.payload,
        error: null
      };
    case FETCH_DATA_FAILURE:
      return {
        ...state,
        loading: false,
        error: action.payload
      };
    default:
      return state;
  }
};

export default authReducer;

Step 2: Implement Redux Saga for Async API Call

Redux Saga will handle the asynchronous API request. We'll listen for the FETCH_DATA action, call your login API, and dispatch success/failure actions based on the response.

// sagas/authSagas.js
import { call, put, takeLatest } from 'redux-saga/effects';
import { FETCH_DATA, fetchDataSuccess, fetchDataFailure } from '../actions/authActions';
import AsyncStorage from '@react-native-async-storage/async-storage';

// Replace this with your actual login API endpoint
async function authenticateUser(username, password) {
  const response = await fetch('https://your-api-domain.com/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username, password })
  });
  
  const data = await response.json();
  
  if (!response.ok || !data.auth_token) {
    throw new Error(data.message || 'Authentication failed');
  }
  
  return data.auth_token;
}

function* fetchDataSaga(action) {
  try {
    const { username, password } = action.payload;
    const authToken = yield call(authenticateUser, username, password);
    
    // Dispatch success action to update Redux state
    yield put(fetchDataSuccess(authToken));
    
    // Optional: Store token locally right here in the saga
    yield call(AsyncStorage.setItem, 'auth_token', authToken);
  } catch (error) {
    // Dispatch failure action with error message
    yield put(fetchDataFailure(error.message));
  }
}

// Listen for the latest FETCH_DATA action (prevents duplicate requests)
export function* watchAuthSagas() {
  yield takeLatest(FETCH_DATA, fetchDataSaga);
}

Step 3: Connect Your Login Component to Redux

Now wire up your login screen to Redux so it can dispatch the fetchData action and react when the authToken is available.

// components/LoginScreen.js
import React, { useState, useEffect } from 'react';
import { View, TextInput, Button, Text, ActivityIndicator, StyleSheet } from 'react-native';
import { connect } from 'react-redux';
import { fetchData } from '../actions/authActions';
import { useNavigation } from '@react-navigation/native'; // If using React Navigation

const LoginScreen = ({ fetchData, loading, authToken, error }) => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const navigation = useNavigation();

  // Trigger follow-up actions when authToken is received
  useEffect(() => {
    if (authToken) {
      // Example: Navigate to home screen
      navigation.navigate('Home');
      
      // Optional: Store token locally here instead of in the saga
      // AsyncStorage.setItem('auth_token', authToken);
    }
  }, [authToken, navigation]);

  const handleLoginPress = () => {
    if (!username.trim() || !password.trim()) {
      alert('Please enter both username and password');
      return;
    }
    fetchData(username, password);
  };

  return (
    <View style={styles.container}>
      <TextInput
        style={styles.input}
        placeholder="Username"
        value={username}
        onChangeText={setUsername}
        autoCapitalize="none"
      />
      <TextInput
        style={styles.input}
        placeholder="Password"
        value={password}
        onChangeText={setPassword}
        secureTextEntry
        autoCapitalize="none"
      />

      {loading ? (
        <ActivityIndicator size="large" color="#007AFF" />
      ) : (
        <Button title="Login" onPress={handleLoginPress} />
      )}

      {error && <Text style={styles.errorText}>{error}</Text>}
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    paddingHorizontal: 20,
  },
  input: {
    borderBottomWidth: 1,
    borderBottomColor: '#ccc',
    marginBottom: 15,
    paddingVertical: 8,
  },
  errorText: {
    color: 'red',
    marginTop: 10,
    textAlign: 'center',
  },
});

// Map Redux state to component props
const mapStateToProps = (state) => ({
  loading: state.auth.loading,
  authToken: state.auth.authToken,
  error: state.auth.error,
});

// Map action creators to component props
const mapDispatchToProps = { fetchData };

export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen);

Step 4: Configure Redux Store with Saga Middleware

Don't forget to set up your Redux store to use the saga middleware so your sagas can run.

// store.js
import { createStore, combineReducers, applyMiddleware } from 'redux';
import createSagaMiddleware from 'redux-saga';
import authReducer from './reducers/authReducer';
import { watchAuthSagas } from './sagas/authSagas';

// Combine all reducers (add more if you have others)
const rootReducer = combineReducers({
  auth: authReducer,
});

// Initialize saga middleware
const sagaMiddleware = createSagaMiddleware();

// Create store with middleware
const store = createStore(rootReducer, applyMiddleware(sagaMiddleware));

// Run your root saga
sagaMiddleware.run(watchAuthSagas);

export default store;

Key Notes to Keep in Mind
  • Token Storage: You can store the auth_token in AsyncStorage either in the saga (right after a successful login) or in the component's useEffect—pick whichever fits your workflow better.
  • Prevent Duplicate Requests: We used takeLatest in the saga, which cancels any pending requests if a new one is triggered (perfect for stopping double-clicks on the login button). If you need to allow concurrent requests, use takeEvery instead.
  • Error Handling: The example shows an error message in the component, but you could also use a toast notification or custom alert for a better user experience.
  • Navigation: If you're not using React Navigation, replace the navigation logic with whatever routing your app uses (e.g., switching screens manually).

内容的提问来源于stack exchange,提问作者Surinder Bhomra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:45:10