React Singleton Hook으로 앱을 정말 섹시하게 만들기

일반 반응 후크에서 싱글톤 후크 만들기

싱글톤 훅이란?


  • 싱글톤 후크는 기능 면에서 React Context와 매우 유사합니다. 각 싱글톤 후크에는 본문이 있으며 컨텍스트 제공자 본문으로 생각할 수 있습니다. 후크에는 반환 값이 있으며 컨텍스트에서 제공하는 값과 유사합니다. 구성 요소에서 싱글톤 후크를 사용하는 것은 컨텍스트를 사용하는 것과 같습니다.
  • 싱글톤 후크가 지연됩니다. 후크가 일부 구성 요소 또는 다른 후크에 의해 호출될 때까지 본문은 실행되지 않습니다. 일단 로드되면 후크 본체는 영원히 로드된 상태로 유지됩니다. 일부 Singleton 후크를 즉시 로드하려면 앱의 최상위 구성 요소에서 사용하십시오.
  • 싱글톤 후크에는 공급자 또는 특수 앱 구조가 필요하지 않습니다. 내부적으로는 성능과 이식성을 위해 useState/useRef/useEffect 및 잘 알려지지 않은 몇 가지 반응 기능을 사용합니다.
  • 단일 앱 Singleton 후크, React-Redux 후크 API, React Context 후크 및 모든 사용자 정의로 혼합할 수 있습니다
  • .

    설치



    React 앱에서 React Singleton Hook을 사용하려면 종속 항목으로 설치하세요.

        # If you use npm:
        npm install react-singleton-hook
    
        # Or if you use Yarn:
        yarn add react-singleton-hook
    


    이것은 npm 또는 Webpack과 같은 모듈 번들러와 함께 Browserify 패키지 관리자를 사용하여 CommonJS modules 을 소비한다고 가정합니다.



    책 받기: React js Hooks PDF



    사용자 지정 후크를 싱글톤 후크로 변환



    아래 코드에서 사용자 프로필은 일부 구성 요소에서 useUserProfile을 사용할 때까지 가져오지 않으며 가져오면 다시 로드되지 않으며 후크는 숨겨진 구성 요소에 영원히 마운트된 상태로 유지됩니다.

        import  { useEffect, useState } from 'react';
        import { singletonHook } from 'react-singleton-hook';
        const api = { async getMe() { return { name: 'test' }; } };
    
        const init = { loading: true };
    
        const useUserProfileImpl = () => {
          const [profile, setProfile] = useState(init);
          useEffect(() => {
            api.getMe()
              .then(profile => setProfile({ profile }))
              .catch(error => setProfile({ error }));
          }, []);
    
          return profile;
        };
    
    
        export const useUserProfile = singletonHook(init, useUserProfileImpl);
    


    다크/라이트 모드 스위치



    Configurator가 darkMode를 변경할 때마다 구독한 모든 구성 요소가 업데이트됩니다.

        /***************    file:src/services/darkMode.js    ***************/  
        import { useState } from 'react';
        import { singletonHook } from 'react-singleton-hook';
    
        const initDarkMode = false;
        let globalSetMode = () => { throw new Error('you must useDarkMode before setting its state'); };
    
        export const useDarkMode = singletonHook(initDarkMode, () => {
          const [mode, setMode] = useState(initDarkMode);
          globalSetMode = setMode;
          return mode;
        });
    
        export const setDarkMode = mode => globalSetMode(mode);
    
    
        /***************    file:src/compoents/App.js    ***************/
    
        import  React from 'react';
        import { useDarkMode, setDarkMode } from 'src/services/darkMode';
    
        const Consumer1 = () => {
          const mode = useDarkMode();
          return <div className={`is-dark-${mode}`}>Consumer1 - {`${mode}`}</div>;
        };
    
        const Consumer2 = () => {
          const mode = useDarkMode();
          return <div className={`is-dark-${mode}`}>Consumer2 - {`${mode}`}</div>;
        };
    
        const Configurator = () => {
          const mode = useDarkMode();
          return <button onClick={() => setDarkMode(!mode)}>Toggle dark/light</button>;
        };
    


    반응하지 않는 코드에 대한 후크 상태를 명령적으로 읽습니다.




        import { useState } from 'react';
        import { singletonHook } from 'react-singleton-hook';
    
        const initDarkMode = false;
        let currentMode = initDarkMode;
        let globalSetMode = () => { throw new Error(`you must useDarkMode before setting its state`); };
    
        export const useDarkMode = singletonHook(initDarkMode, () => {
          const [mode, setMode] = useState(initDarkMode);
          globalSetMode = setMode;
          currentMode = mode;
          return mode;
        });
    
        export const setDarkMode = mode => globalSetMode(mode);
        export const getDarkMode = () => currentMode;
    


    singletonHook 내에서 react-redux(또는 다른 컨텍스트) 사용



    react-redux 또는 기타 컨텍스트 기반 기능을 사용하려면 앱의 공급자 아래에 싱글톤 후크를 마운트해야 합니다. 그렇게 하려면 react-singleton-hook에서 SingletonHooksContainer를 가져오고 앱의 아무 곳에나 마운트하세요. SingletonHooksContainer는 싱글톤 후크를 사용하는 구성 요소보다 먼저 렌더링되어야 합니다! 기본적으로 SingletonHooksContainer로 전화를 걸 필요가 없으며 별도의 반응 앱에서 내부적으로 이 구성 요소를 실행합니다.

        /***************    file:src/services/currentUser.js    ***************/
        import { singletonHook } from 'react-singleton-hook';
        import { useSelector } from 'react-redux';
    
        const init = { loading: true };
        const useCurrentUserImpl = () => {
          const session = useSelector(state => state.session);
          if (session.loading) return init;
          return session.user;
        };
    
        export const useCurrentUser = singletonHook(init, useCurrentUserImpl);
    
        /***************    file:src/App.js    ***************/
    
        import React from 'react';
        import ReactDOM from 'react-dom';
        import { SingletonHooksContainer } from 'react-singleton-hook';
        import { Provider } from 'react-redux';
        import store from 'src/store';
        import App from 'src/views';
    
        const app = (
          <Provider store={store}>
            <>
              <SingletonHooksContainer/>
              <App/>
            </>
          </Provider>
        );
    
        ReactDOM.render(app, document.getElementById('root'));
    
    ### top-level components updated before low-level components
    
        /***************    file:src/services/session.js    ***************/
    
        import { useEffect, useState } from 'react';
        import { singletonHook } from 'react-singleton-hook';
    
        const initState = { loading: true };
        let setSessionGlobal = () => { throw new Error('you must useSession before login'); };
    
        const useSessionImpl = () => {
          const [session, setSession] = useState(initState);
          setSessionGlobal = setSession;
          useEffect(() => { setSession({ loggedIn: false }); }, []);
          return session;
        };
    
        export const useSession = singletonHook(initState, useSessionImpl);
    
        export const login = (name, pass) => {
          setSessionGlobal({ loggedIn: true, user: { name: 'test' } });
        };
    
        /***************    file:src/index.js    ***************/
        import React, { useEffect } from 'react';
        import ReactDOM from 'react-dom';
        import { login, useSession } from 'src/services/session';
    
        const LoggedInView = () => {
          const session = useSession();
          console.log(`LoggerInView rendered with ${JSON.stringify(session)}`);
          return null;
        };
    
        const LoggedOutView = () => {
          const session = useSession();
          console.log(`LoggedOutView rendered with ${JSON.stringify(session)}`);
          return null;
        };
    
        const WaitingForSessionView = () => {
          const session = useSession();
          console.log(`WaitingForSessionView rendered with ${JSON.stringify(session)}`);
          return null;
        };
    
        const MainComponent = () => {
          const session = useSession();
    
          useEffect(() => {
            setTimeout(() => { login('testuser'); }, 2000);
          }, []);
    
          console.log(`MainComponent rendered with ${JSON.stringify(session)}`);
    
          if (session.loading) return <WaitingForSessionView/>;
          if (session.loggedIn) return <LoggedInView/>;
          return <LoggedOutView/>;
        };
    
    
        ReactDOM.render(<MainComponent/>, document.getElementById('root'));
    
        /***************    console.log    ***************/
        /*
    
        MainComponent rendered with {"loading":true}
        WaitingForSessionView rendered with {"loading":true}
        MainComponent rendered with {"loggedIn":false}
        LoggedOutView rendered with {"loggedIn":false}
        MainComponent rendered with {"loggedIn":true,"user":{"name":"test"}}
        LoggerInView rendered with {"loggedIn":true,"user":{"name":"test"}}
    
        */
    


    초기 상태 콜백



    버전 3.0부터 singletonHook는 미리 정의된 초기 상태 대신 초기 상태를 계산하는 콜백을 허용합니다. 이 콜백은 값이 필요할 때만 한 번 호출됩니다. 비용이 많이 드는 초기 값을 계산하거나 구성 요소가 후크를 사용하기 전에 초기 상태가 변경될 때 추가 렌더링(및 상태 깜박임)을 방지하는 데 사용할 수 있습니다.

    예: 기존 get/set 데이터 모듈에 대한 구성 요소 구독




        /***************    file:src/services/darkMode.js    ***************/
    
        import { useState } from 'react';
        import { singletonHook } from 'react-singleton-hook';
    
        let isDarkMode = false; // the state of the module
        let updateSubscribers = (mode) => {}; //update subscribers callback - do nothing by default
    
        // pre-existing functions to manipulate the state
        export const getDarkMode = () => isDarkMode;
    
        export const setDarkMode = (newMode) => {
         isDarkMode = newMode;
         updateSubscribers(isDarkMode); // call updateSubscribers when setting new state
        };
    
        // new function - custom hook for components to subscribe.
        // using getDarkMode as an init callback to get most relevant state
        export const useDarkMode = singletonHook(getDarkMode, () => {
         const [mode, setMode] = useState(getDarkMode);
         updateSubscribers = setMode; // subscribing for further updates
         return mode;
        });
    
        /***************    file:src/index.js    ***************/
    
        // you can call setter and getter any time
        setDarkMode(true);
        setInterval(() => setDarkMode(!getDarkMode()), 2000);
    
        const App = () => {
         // component will be updated on darkMode change 
         // on first render "mode" is set to the current value getDarkMode returns
         const mode = useDarkMode();
         return <div className={`is-dark-${mode}`}>App - {`${mode}`}</div>;
        };
    


    Github: https://github.com/Light-Keeper/react-singleton-hook

    React를 배우기 위한 추가 리소스:

    반응과 장고 | 전자상거래 웹사이트



    Redux Saga(React 및 Redux 포함): 빠른 소개 과정

    좋은 웹페이지 즐겨찾기