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

如何在Redux的Action/Service中访问Store?重复代码优化咨询

How to Reuse "Check Cache Before Fetching" Logic in Redux

Hey there! No worries at all—switching from Ember to React+Redux takes time, and it’s totally normal to hit these little roadblocks as you learn the patterns. Let’s break down how you can eliminate that repeated code and handle the "check cache first, fetch if missing" logic properly.

1. Use Redux Thunk to Add Logic to Action Creators

The most common way to handle this is with Redux Thunk (a middleware that lets your action creators return functions instead of plain objects). These functions get access to dispatch and getState, so you can check the current store state before deciding to fetch data.

First, make sure you have Redux Thunk set up in your store (most Redux apps use it by default). Then, create a reusable action creator like this:

// userActions.js
export const getProfile = (userId) => async (dispatch) => {
  // Your existing API fetch logic here
  const response = await fetch(`/api/profiles/${userId}`);
  const profileData = await response.json();
  dispatch({ type: 'PROFILE_FETCH_SUCCESS', payload: profileData });
};

// The new reusable action that checks cache first
export const getProfileIfNeeded = (userId) => (dispatch, getState) => {
  // Get the current profiles from the store
  const { profiles } = getState().profileaccounts;
  
  // Check if the profile already exists
  const existingProfile = profiles.find(prof => prof.profile.id === userId);
  
  if (!existingProfile) {
    // Only fetch if it's not in the cache
    return dispatch(getProfile(userId));
  }
  
  // If it exists, return the cached data (as a Promise for consistency)
  return Promise.resolve(existingProfile);
};

Then, in all your components, replace that repeated componentDidMount code with:

componentDidMount() {
  const { user, dispatch } = this.props;
  dispatch(getProfileIfNeeded(user.id));
}

2. Use a Custom Hook (For Functional Components)

If you’re moving towards functional components (the modern React approach), wrap this logic in a custom hook for even easier reuse:

// hooks/useProfile.js
import { useSelector, useDispatch } from 'react-redux';
import { getProfileIfNeeded } from '../actions/userActions';
import { useEffect } from 'react';

export const useProfile = (userId) => {
  const dispatch = useDispatch();
  const profiles = useSelector(state => state.profileaccounts.profiles);
  const currentProfile = profiles.find(prof => prof.profile.id === userId);

  useEffect(() => {
    if (userId && !currentProfile) {
      dispatch(getProfileIfNeeded(userId));
    }
  }, [userId, currentProfile, dispatch]);

  return currentProfile;
};

Now any functional component can use this hook in one line:

const profile = useProfile(user.id);

3. For Class Components: Use a Higher-Order Component (HOC)

If you’re sticking with class components, create an HOC that injects the profile and handles the fetch logic:

// hoc/withProfile.js
import React from 'react';
import { connect } from 'react-redux';
import { getProfileIfNeeded } from '../actions/userActions';

const withProfile = (WrappedComponent) => {
  class WithProfile extends React.Component {
    componentDidMount() {
      const { user, getProfileIfNeeded } = this.props;
      if (user?.id) {
        getProfileIfNeeded(user.id);
      }
    }

    componentDidUpdate(prevProps) {
      // Re-fetch if the user changes
      if (this.props.user?.id !== prevProps.user?.id) {
        this.props.getProfileIfNeeded(this.props.user.id);
      }
    }

    render() {
      const { profiles, user, ...rest } = this.props;
      const currentProfile = profiles.find(prof => prof.profile.id === user?.id);
      return <WrappedComponent profile={currentProfile} {...rest} />;
    }
  }

  const mapStateToProps = state => ({
    profiles: state.profileaccounts.profiles
  });

  const mapDispatchToProps = {
    getProfileIfNeeded
  };

  return connect(mapStateToProps, mapDispatchToProps)(WithProfile);
};

export default withProfile;

Then wrap your components with it:

class MyComponent extends React.Component {
  render() {
    const { profile } = this.props;
    // Use profile here
  }
}

export default withProfile(MyComponent);

Key Takeaway

You don’t need to access the store directly from services—instead, use middleware like Redux Thunk to let your action creators check the store state before triggering API calls. This keeps your logic centralized and eliminates duplicate code across components.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:02:17