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
相关产品推荐
相关产品推荐

