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

React-Redux如何连接Express+MySQL后端获取数据?

Great question—this is one of the most common sticking points when you’re first tying Redux to a backend API. Let’s clear this up with concrete examples and the standard best practices used in the React/Redux ecosystem.

First: Never fetch data inside a reducer

Redux reducers are pure functions—they should only take the current state and an action, then return a new state. They can’t contain side effects like API calls, database queries, or fetch() requests. Doing so breaks Redux’s core principles and will lead to unpredictable state updates.

The standard solution: Async action creators with Redux Thunk

The best practice here is exactly what you hinted at: handle API calls in action creators, using a middleware like Redux Thunk to support asynchronous logic in actions. Redux Thunk lets you write action creators that return functions instead of plain objects, so you can delay dispatching actions until the API call completes.

Let’s walk through a full example matching your setup:


1. Backend: Express/MySQL users.js (your existing setup)

First, confirm your backend route is working to return users:

// backend/routes/users.js
const express = require('express');
const router = express.Router();
const mysql = require('mysql');

// Configure DB connection
const db = mysql.createConnection({
  host: 'localhost',
  user: 'your_db_user',
  password: 'your_db_password',
  database: 'your_db_name'
});

// Get all users
router.get('/', (req, res) => {
  db.query('SELECT * FROM users', (err, results) => {
    if (err) {
      return res.status(500).json({ error: err.message });
    }
    res.json(results);
  });
});

module.exports = router;

2. Redux Setup: Install dependencies

First, add the tools you’ll need:

npm install redux-thunk axios
  • redux-thunk: The middleware to handle async actions
  • axios: A popular library for making API requests (you can use native fetch too)

3. Configure Redux Store with Thunk

Update your store to use the Thunk middleware:

// store.js
import { createStore, applyMiddleware, combineReducers } from 'redux';
import thunk from 'redux-thunk';
import userReducer from './reducers/userReducer';

const rootReducer = combineReducers({
  users: userReducer // Your user state will live under `state.users`
});

// Apply Thunk middleware to support async actions
const store = createStore(rootReducer, applyMiddleware(thunk));

export default store;

4. Write Async Action Creator

Create an action creator to handle fetching users, including loading and error states:

// actions/userActions.js
import axios from 'axios';

// Action types (best practice to avoid typos)
export const FETCH_USERS_REQUEST = 'FETCH_USERS_REQUEST';
export const FETCH_USERS_SUCCESS = 'FETCH_USERS_SUCCESS';
export const FETCH_USERS_FAILURE = 'FETCH_USERS_FAILURE';

// Async action creator
export const fetchUsers = () => {
  return (dispatch) => {
    // Dispatch a "loading" action first
    dispatch({ type: FETCH_USERS_REQUEST });
    
    // Make API call
    axios.get('/users')
      .then(response => {
        // Dispatch success action with user data
        dispatch({ 
          type: FETCH_USERS_SUCCESS, 
          payload: response.data 
        });
      })
      .catch(error => {
        // Dispatch failure action with error message
        dispatch({ 
          type: FETCH_USERS_FAILURE, 
          payload: error.message 
        });
      });
  };
};

5. Update Reducer to Handle Actions

Modify your user reducer to respond to the async actions and update state:

// reducers/userReducer.js
import {
  FETCH_USERS_REQUEST,
  FETCH_USERS_SUCCESS,
  FETCH_USERS_FAILURE
} from '../actions/userActions';

const initialState = {
  loading: false,
  users: [], // Start empty, as you had before
  error: ''
};

const userReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCH_USERS_REQUEST:
      return {
        ...state,
        loading: true
      };
    case FETCH_USERS_SUCCESS:
      return {
        loading: false,
        users: action.payload, // Populate users from API response
        error: ''
      };
    case FETCH_USERS_FAILURE:
      return {
        loading: false,
        users: [],
        error: action.payload
      };
    default:
      return state;
  }
};

export default userReducer;

6. Dispatch the Action in Your Component

In your component, dispatch the fetchUsers action when the component mounts. Here’s how to do it for both class and function components:

Class Component:
// components/UserList.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchUsers } from '../actions/userActions';

class UserList extends Component {
  componentDidMount() {
    // Dispatch the async action when the component loads
    this.props.fetchUsers();
  }

  render() {
    const { loading, users, error } = this.props;
    return (
      <div>
        <h2>User List</h2>
        {loading && <p>Loading users...</p>}
        {error && <p className="error">Error: {error}</p>}
        <ul>
          {users.map(user => (
            <li key={user.id}>{user.name} - {user.email}</li>
          ))}
        </ul>
      </div>
    );
  }
}

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

// Map dispatch to component props
const mapDispatchToProps = (dispatch) => {
  return {
    fetchUsers: () => dispatch(fetchUsers())
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(UserList);
Function Component (with Hooks):
// components/UserList.js
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchUsers } from '../actions/userActions';

const UserList = () => {
  const dispatch = useDispatch();
  const { loading, users, error } = useSelector(state => state.users);

  useEffect(() => {
    // Dispatch the action on component mount
    dispatch(fetchUsers());
  }, [dispatch]);

  return (
    <div>
      <h2>User List</h2>
      {loading && <p>Loading users...</p>}
      {error && <p className="error">Error: {error}</p>}
      <ul>
        {users.map(user => (
          <li key={user.id}>{user.name} - {user.email}</li>
        ))}
      </ul>
    </div>
  );
};

export default UserList;

Key Takeaways

  • Keep reducers pure: No API calls, side effects, or async logic here—they only update state based on actions.
  • Async logic lives in action creators: Use middleware like Redux Thunk to handle delayed action dispatching.
  • Track request states: Include loading/error states in your reducer to give users feedback while data loads.
  • Trigger actions in component lifecycle: Dispatch the async action when your component mounts (or when a user interacts with it, like clicking a button).

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:35:12