考虑 React 中模式实现的最佳实践

模态实现在有限元开发中无处不在,随着需求和模态数量的增加,实现变得复杂,很多人对设计感到厌烦。

所以我想到了模态实现的最佳实践

设计方针

我决定为 Recoil 和状态管理的模态逻辑制作自定义钩子。

使用 Recoil 的原因是 Recoil 提供的状态管理的atomFamily 与模态实现非常兼容。

模态实现的反模式

主页.tsx

const MainPage = () => {
  const [isFaqVisible, setIsFaqVisible] = useState(false)

  return (
    <div>
      {isFaqVisible && <FaqModal />}
      <button onClick={() => setIsFaqVisible(true)}>
        クリックするとFAQモーダルが開くよ
      </button>
    </div>
  )
}

export default MainPage

虽然是一定的写法,但是如果像这样在同一个组件中有modal的开启和关闭状态,就会出现如下缺点

  • 由于打开和关闭以及显示状态完全依赖于组件,因此很难从另一个组件打开和关闭。特别是由于它预计会从FAQ modal等许多页面调用,它很可能成为意外错误的温床。
  • 随着要显示的模式数量的增加,状态也会增加,从而使代码的可预测性和可维护性降低。

解决方案

  • 打开/关闭状态和处理与自定义挂钩松散耦合
  • 通过atomFamily抽象模态状态,消除了状态的冗余描述

模态状态管理

src/states/modal.ts

import { atomFamily } from 'recoil'

export type ModalType =
  | 'contact'
  | 'faq'
  | 'confirm'
export const ModalVisibilityState = atomFamily({
  key: 'ModalVisibilityState',
  default: false,
})

这里,模态状态由ModalTypeatomFamily 抽象,具体取决于模态类型。

常见问题模式

FAQ.tsx

import Modal from 'components/Common/Modal'
import useModalWindow from 'hooks/useModalWindow'

const FaqModal = () => {
  const [isVisible, setIsVisible] = useModalWindow('faq')

  return (
    isVisible && (
      // propsにモーダルを閉じるcomponent
      <Modal closeModal={() => setIsVisible(false)}>{/*Modalの中身*/}</Modal>
    )
  )
}

export default FaqModal

关键是它可以在不知道调用者的打开/关闭状态的情况下通过仅显示/隐藏组件内部的关注点来实现。

模态自定义钩子

src/hooks/useModal.ts

import { useRecoilState, SetterOrUpdater } from 'recoil'
import { ModalVisibilityState, ModalType } from 'states/modal'

type Response = [
  boolean,
  SetterOrUpdater<boolean>
]

const useModalWindow = (modalType: ModalType): Response => {
  const [isVisible, setIsVisible] = useRecoilState(
    ModalVisibilityState(modalType)
  )

  return [isVisible, setIsVisible]
}

export default useModalWindow

atomFamily 创建的ModalVisibilityStateuseRecoilState 包裹,以创建唯一的状态并管理打开/关闭过程。

这样一来,就不用一一描述每个模态的状态了,会让人耳目一新

此外,通过将ModalType 作为参数传递,您可以从任何组件灵活地打开它。

要显示模态的组件

DisplayModalComponent.tsx

import React from 'react'
import FaqModal from 'components/Modal/FaqModal'

const DisplayModalComponent = () => {
  return (
   <FaqModal />
  )
}

export default DisplayModalComponent

您要调用模态的组件

CallModalComponent.tsx

import useModalWindow from 'hooks/useModalWindow'

const CallModalComponent = () => {
  const [, setIsVisible] = useModalWindow("faq")

  return (
    <button onClick={() => setIsVisible(true)}>
      クリックするとFAQモーダルが開くよ
    </button>
  )
}



export default CallModalComponent

拨打useModalWindow并点击按钮打开FAQ模式

考虑

我认为还有其他方法可以使用上下文或 RecoilRoot 来管理全局状态,但是这种编写方式更简洁,我认为这是我个人目前的最佳实践!

原创声明:本文系作者授权爱码网发表,未经许可,不得转载;

原文地址:https://www.likecs.com/show-308623570.html