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

遵循DRY原则生成React Context:替代eval的更优写法

问题

现有两段结构高度相似的React Context实现代码:

const CourseContext = createContext()
const CourseProvider = ({children}) => {
    const [course, setCourse] = useState(null);
    return (
        <CourseContext.Provider value={{course, setCourse}}>
            {children}
        </CourseContext.Provider>
    )
}

以及:

const SaleContext = createContext()
const SaleProvider = ({children}) => {
    const [sale, setSale] = useState({name: "A great course", price: 25});
    return (
        <SaleContext.Provider value={{sale, setSale}}>
            {children}
        </SaleContext.Provider>
    )
}

为了避免重复编写这类结构,我希望能根据状态变量名(比如"course"或"sale")和初始值(比如null或{name: "A great course", price: 25})快速生成Context。我知道用eval可以实现,但有没有更简洁、更符合JavaScript惯用写法的方法?


解决方案

当然有,完全不用eval,我们可以写一个通用的工厂函数来封装重复逻辑,这是更符合JS最佳实践的方式。

实现通用工厂函数

这个函数接收状态变量名和初始值两个参数,返回包含Context和对应Provider的对象:

import { createContext, useState } from 'react';

function createStateContext(stateName, initialValue) {
  const Context = createContext();
  
  const Provider = ({ children }) => {
    const [state, setState] = useState(initialValue);
    // 动态构造包含状态和修改函数的value对象,比如{course: ..., setCourse: ...}
    const value = {
      [stateName]: state,
      // 自动生成首字母大写的setter函数名
      [`set${stateName.charAt(0).toUpperCase()}${stateName.slice(1)}`]: setState
    };
    
    return (
      <Context.Provider value={value}>
        {children}
      </Context.Provider>
    );
  };
  
  return { Context, Provider };
}

使用方式

现在生成Course和Sale对应的Context就变得非常简洁:

// 生成Course相关的Context和Provider
const { Context: CourseContext, Provider: CourseProvider } = createStateContext('course', null);

// 生成Sale相关的Context和Provider
const { Context: SaleContext, Provider: SaleProvider } = createStateContext('sale', {name: "A great course", price: 25});

为什么这比eval更好

  • 安全性更高:eval会执行任意字符串,存在代码注入风险,而工厂函数是纯逻辑封装,没有安全隐患
  • 可读性更强:代码逻辑清晰,一眼就能看出是生成状态Context的工具函数
  • 可维护性更好:后续要修改Provider逻辑(比如添加useEffect、状态校验),只需要修改工厂函数一处即可

扩展优化(可选)

如果需要自定义修改函数名,或者添加其他共享逻辑,还可以给工厂函数加额外参数:

function createStateContext(stateName, initialValue, setStateName) {
  // 默认使用首字母大写的setter命名,支持自定义
  const finalSetStateName = setStateName || `set${stateName.charAt(0).toUpperCase()}${stateName.slice(1)}`;
  const Context = createContext();
  
  const Provider = ({ children }) => {
    const [state, setState] = useState(initialValue);
    const value = {
      [stateName]: state,
      [finalSetStateName]: setState
    };
    
    return (
      <Context.Provider value={value}>
        {children}
      </Context.Provider>
    );
  };
  
  return { Context, Provider };
}

自定义修改函数名的使用示例:

const { Context: SaleContext, Provider: SaleProvider } = createStateContext('sale', {name: "A great course", price: 25}, 'updateSale');

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 06:20:20