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

React Redux环境下如何简化connect的状态映射函数写法?

优化React-Redux connect的状态映射代码:更简洁的写法?

在React & Redux环境中,组件会接收特定的Redux状态,示例状态如下:

state = { 
  users: ['bob', 'alice'], 
  history: {param: 1}, 
  releases: [1, 2], 
  categories: [1, 2, 3], 
  store: {dispatch: () => (), subscribe: () => ()}, 
  contact: {message: ""}, 
  hosts: ['company1', 'company2'], 
  experiences: ['xp1', 'xp2'], 
}

当前我编写组件的方式如下:

import React, {Component} from "react"; 
import {connect} from "react-redux"; 

@connect(state => ({ 
  hosts: state.hosts, 
  experiences: state.experiences, 
  categories: state.categories, 
})) 
export default class Home extends Component { ... }

我一直在尝试寻找缩减传递给connect的状态映射函数代码量的方法,尝试过以下几种写法:

@connect(({hosts, experiences, categories}) => ({hosts, experiences, categories}))
@connect(state => _.pick(state, ['hosts', 'experiences', 'categories']))
@connect(({users, history, releases, store, contact, ...rest}) => rest)

但这些写法在可读性和DRY原则方面都不尽如人意。既然我们有扩展运算符和剩余运算符,为何无法消除这种冗余映射?像以下几种写法会简洁得多:

@connect(({hosts, experiences, categories}) => ...)
@connect(...({hosts, experiences, categories}))
@connect(() => ({hosts, experiences, categories}))
@connect(({hosts, experiences, categories}))

请问是否存在我尚未了解的更优写法?


嘿,这个问题我太有共鸣了——谁不想少写点重复的状态映射代码呢?我来分享几个在项目里亲测好用、兼顾简洁性和可读性的方案:

1. 自定义pickState工具函数

这是我最常用的方案,自己封装一个轻量的工具函数,专门用来从Redux state中挑选需要的字段,复用性拉满:

// 可以放在项目的utils/redux.js文件中统一管理
export const pickState = (...keys) => (state) => {
  return keys.reduce((acc, key) => {
    acc[key] = state[key];
    return acc;
  }, {});
};

之后在组件里使用就超级清爽,一眼就能看出你取了哪些状态字段:

import { pickState } from './utils/redux';

@connect(pickState('hosts', 'experiences', 'categories'))
export default class Home extends Component { ... }

2. 结合Redux Toolkit的createSelector(推荐用于复杂场景)

如果你已经在使用Redux官方推荐的Redux Toolkit(RTK),可以用它的createSelector来创建复用的状态选择器。虽然对于简单的字段提取,它比上面的pickState稍显繁琐,但如果后续需要对状态做转换、或者需要利用它的缓存特性(避免不必要的重渲染),优势就很明显了:

import { createSelector } from '@reduxjs/toolkit';
import { connect } from 'react-redux';

// 先定义单个字段的选择器
const selectHosts = (state) => state.hosts;
const selectExperiences = (state) => state.experiences;
const selectCategories = (state) => state.categories;

// 组合成组件需要的props映射
const selectHomeProps = createSelector(
  [selectHosts, selectExperiences, selectCategories],
  (hosts, experiences, categories) => ({
    hosts,
    experiences,
    categories
  })
);

@connect(selectHomeProps)
export default class Home extends Component { ... }

3. 优化后的解构赋值写法(兼顾简洁与可读)

如果你不想额外封装工具函数,也可以把你之前的解构写法稍微调整得更紧凑一点,虽然还是有少量重复,但可读性比_.pick或者剩余运算符要好很多——毕竟不用去翻数组或者猜测rest里包含哪些字段:

@connect(({ hosts, experiences, categories }) => ({ hosts, experiences, categories }))

为什么你设想的那些写法行不通?

顺便解释下你提到的几种简洁写法为什么无法工作:

  • @connect(({hosts, experiences, categories}) => ...):箭头函数如果省略大括号,会把后面的内容当成返回值,但...在这里语法无效,如果你想返回解构后的对象,必须写成({ hosts, experiences, categories })(加括号让解析器识别为对象字面量)。
  • @connect(...({hosts, experiences, categories})):展开对象的键会得到三个字符串,但connect需要接收的是一个状态映射函数,不是字符串参数,所以会报错。
  • @connect(() => ({hosts, experiences, categories})):这个写法是直接返回一个固定对象,而不是从Redux state中获取对应字段,完全不符合需求。
  • @connect(({hosts, experiences, categories})):这里你直接传递了解构后的对象,但connect第一个参数需要是函数,不是对象,所以运行时会抛出错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 04:28:18