反応におけるモダールの使用JS,正しい方法(ゼロ支柱掘削)


モーダルを制御するのは、次のような効果を書くのは簡単だった.
const someModal = useModal()

useEffect(() => {
  if (someModal.isOpen) {
    setTimeout(someModal.close, 1000)
  }
}, [someModal])
私の名前はiTay Schechnerです、そして、私は特に反応で特にフロントエンドコードの後ろで専門になっている成長しているfullstack開発者です.js
この記事では、読みやすく、再利用可能なモーダルユーティリティを書く方法を教えます.

NOTE: This article is heavily based on I wrote, explaining usage of the Context API in detail.


今日は何を学びますか
  • USemodalフック
  • の使用法
  • モーダルコンポーネント工場
  • モーダルファクトリを使用して読みやすいコードを書く.
    モードフック
    いくつかのタイプスクリプトから始めましょう.
    export interface Modal {
      isOpen: boolean;
      open(): void;
      close(): void;
    }
    
    それから、それぞれのモーダルが開くことができると理解しています.このフックは実装が比較的簡単です.
    export default function useModal(): Modal {
      const [isOpen, setOpen] = useState(false);
      return {
        isOpen,
        open() {
          setOpen(true);
        },
        close() {
          setOpen(false);
        },
      };
    }
    
    あなたは、このフックをあなたの構成要素のうちの1つで使用することによってモーダルロジックを実装することができます、そして、多くのプロップ穴を使って.例えば、
    export default function Navbar ()  {
        const { isOpen, open, close } = useModal();
        return (
            <nav>
             // ...navigation code
             { isOpen && <Modal close={close} /> }
             <button onClick={open}>Open Modal</button>
            </nav>
        )
    }
    
    私たちはこのようにコンポーネントを書くのにとても慣れているので、私たちはmodalsの完全な可能性を認識しません.モーダルファイルのエクスポートが次のようになります.
    import LoginModal, { LoginModalOpener } from '../auth/LoginModal';
    

    モーダルファクトリー
    我々が議論した前のコンポーネント工場とは異なり、この工場はずっと複雑になるでしょう.
    再び、いくつかのタイプスクリプトで、この工場の要件を見てみましょう.
    export function createModal<T extends object>(
      context: Context<T>,
      name: keyof T,
      openerLabel: string
    ) { ... }
    
    それから何を理解しますか.
  • 関数は、提供されたコンテキストでモーダルタイプのフィールドを取得し、モーダル
  • を作成するために使用します
  • この関数はOpenerLabelフィールドを受け取ります.
  • 我々がオープナーを提供するならば、我々は同様により近くを提供することができなければなりません.テキストの代わりにXアイコンを表示したいので、コンテキストアクションファクトリをアップグレードします.
  • type JSXProvider<Props> = (props: Props) => JSX.Element;
    
    export function action<T extends object, Props extends object = {}>(
      label: string | JSXProvider<Props>, 
      context: React.Context<T>,
      consumer: (ctx: T) => void,
    ) {
      return function ContextAction({ className, ...props }: withClass & Props) {
        const ctx = useContext(context);
        const action = useCallback(() => consumer(ctx), [ctx]);
        return (
          <button onClick={action} className={className}>
            {typeof label === 'string' ? label : label(props as unknown as Props)}
          </button>
        );
      };
    }
    
    さて、モーダルファクトリーを書くことができます.
    export function createModal<T extends object>(
      context: Context<T>,
      name: keyof T,
      openerLabel: string
    ) {
      return {
        Visible: createWrapper(
          context,
          ctx => (ctx[name] as unknown as ModalHook).isOpen
        ),
        Opener: action(openerLabel, context, ctx =>
          (ctx[name] as unknown as Modal).open()
        ),
        // Clear: A JSXProvider that takes width and height props
        Closer: action(Clear, context, ctx => 
          (ctx[name] as unknown as Modal).close()
        ),
      };
    }
    
    きれいなコードを作るためにどのようにこの工場を使用するかを見ましょう.私はあなたを表示する例では、私は、アプリケーション内のアプリケーション全体のために提供される認証コンテキストでログインモードを作成します.TSXファイル.
    // AuthContext.tsx
    export default function AuthContextProvider({ children }: Wrapper) {
      // other auth state ommited for bravety
      const loginModal = useModal();
    
      // effects ommitted for bravety
    
      return (
        <AuthContextProvider value={{ loginModal, ...anything }}>{ children }</AuthContextProvider>
      )
    } 
    
    // LoginModal.tsx
    
    const ModalProvider = createModal(AuthContext, 'loginModal', 'Log In');
    
    export const LoginModalOpener = ModalProvider.Opener;
    
    export default function LoginModal() {
        return (
            <ModalProvider.Visible> // modal is hidden when hook state is hidden
                // Modal UI (i.e dark fixed background, white modal)
                <ModalProvider.Closer />
                <div>
                    // form ommited for bravety
                </div>
            </ModalProvider.Visible>
        )
    }
    
    // App.tsx
    
    export default function App () {
        return (
            <AuthContextProvider>
                <LoginModal />
                <Navbar />
                // rest of application
            </AuthContextProvider>
        )
    }
    
    
    では、Navbarコンポーネントがどれだけシンプルになるかを見てみましょう.
    import { LoginModalOpener } from '../auth/LoginModal';
    
    export default function Navbar () {
        return (
            // ... links ommited for bravety
            <LoginModalOpener />
        )
    }
    

    ラッピング
    あなたが私が間違いをしたと思うならば、または、私はポストをよりよく書くことができました、提案をしてください.
    これを使ったプロジェクト

    itays123 / partydeck
    クールなオンラインカードゲーム!