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

React函数组件公共逻辑提取:如何封装可访问调用方作用域的release函数

方案:使用React自定义Hook抽离公共逻辑

自定义Hook是React官方提供的专门用于抽离组件公共状态与逻辑的特性,天生可以和调用它的组件的上下文适配,完全满足你需要访问调用方内部变量方法的需求。

第一步:简化示例的抽离实现

先针对你给出的最简重复代码做抽离,新建公共Hook文件比如src/hooks/useRelease.js:

import { useState } from 'react'

// 自定义Hook必须以use开头,React才能正确识别
export const useRelease = () => {
  const [isReleased, setIsReleased] = useState(false)
  const release = () => {
    setIsReleased(true)
  }
  // 返回组件需要用到的状态和方法
  return { isReleased, release }
}

在各个组件中直接导入使用即可,每个组件调用Hook会生成独立的状态副本,互不干扰:

import { useRelease } from '@/hooks/useRelease'

const Customer = () => {
  const { isReleased, release } = useRelease()
  // 后续业务逻辑正常使用isReleased、release即可
}

const Order = () => {
  const { isReleased, release } = useRelease()
  // 和Customer组件的状态完全独立,不会互相影响
}

第二步:适配复杂版release逻辑

你补充的代码中this.指代的都是调用组件的内部变量/方法,只需要把这些依赖作为参数传入自定义Hook即可,公共Hook改造如下:

// react-router v6请把useHistory换成useNavigate
import { useHistory } from 'react-router-dom'

export const useRelease = (action, componentContext) => {
  const history = useHistory()
  // 解构出组件传入的所有内部变量、方法
  const {
    dataMode,
    setMessage,
    setFormStatus,
    customer_api_create,
    customer_api_update,
    formData,
    openMessageBox,
    constants,
    setFormData,
    setShouldRecordDeleted
  } = componentContext

  const release = () => {
    if (action === "new") {
      history.push(`/customers/new`)
    } else if (action === "save") {
      (async () => {
        try {
          if (dataMode === "new") {
            setMessage()
            setFormStatus("updating")
            let _res = await customer_api_create(formData)
            if ((_res.status === 200) && (_res.data.status === "success")) {
              setFormStatus()
              history.replace({ pathname: `/customers/${_res.data.data[0].id}` })
            }
          } else if (dataMode === "edit") {
            setFormStatus("updating")
            setMessage()
            let _res = await customer_api_update(formData)
            if ((_res.status === 200) && (_res.data.status === "success")) {
              setFormStatus()
              setMessage({ type: "info", text: "Saved" })
              setFormData(_res.data.data[0])
            }
          }
        } catch (e) {
          openMessageBox({
            prompt: e.response.data.message,
            type: constants.app.MessageBoxType.MB_Error,
            buttons: constants.app.MessageBoxButton.MB_Ok,
            show: true,
            setResult: () => console.log(constants.app.MessageBoxResult.MB_Ok)
          })
          setFormStatus("updating_error")
        }
      })();
    } else if (action === "del") {
      openMessageBox({
        prompt: `{ "": ["Are you sure you want to delete context customer?"] }`,
        type: constants.app.MessageBoxType.MB_Warning,
        buttons: constants.app.MessageBoxButton.MB_YesNo,
        show: true,
        setResult: (val) => {
          openMessageBox({ show: false })
          setShouldRecordDeleted(val)
        }
      })
    }
  }

  return { release }
}

组件中调用方式:

import { useRelease } from '@/hooks/useRelease'

const Customer = () => {
  // 组件内正常定义所有需要的状态、方法、常量
  const [dataMode, setDataMode] = useState('new')
  const [formData, setFormData] = useState({})
  const setMessage = () => {/* 你的原有逻辑 */}
  // ...其余所需方法、常量正常定义

  // 调用自定义Hook,传入当前组件的相关参数
  const { release } = useRelease(action, {
    dataMode,
    setMessage,
    setFormStatus,
    customer_api_create,
    customer_api_update,
    formData,
    openMessageBox,
    constants,
    setFormData,
    setShouldRecordDeleted
  })

  // 后续正常调用release()即可,逻辑和你原有写法完全一致
}

注意事项

  • 如果不同组件的逻辑有小部分差异,可以把差异部分作为回调函数传入Hook,实现更灵活的复用
  • 所有React Hook的使用规则在自定义Hook中同样生效,不要在条件判断、循环中调用自定义Hook

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.11 16:18:01