iT邦幫忙

2023 iThome 鐵人賽

DAY 11
0
Modern Web

設計系統 - Design System系列 第 11

[Day 11] Design System - Common Hook (一)

  • 分享至 

  • xImage
  •  

本系列文章會在筆者的部落格繼續連載!Design System 101 感謝大家的閱讀!

前言

稍微繁忙的一天!決定先介紹兩個 Design System 常用的 Hooks useSafeLayoutEffect 以及 useComposedRefs!

useSafeLayoutEffect

用途

useLayoutEffect 是 React 提供的一個 Hook,跟 useEffect 一樣,都是用來處理 Side Effect 的,不同的是 useLayoutEffect 其執行時間是瀏覽器繪製 DOM 之前,且在 SSR 的時候,會噴出錯誤:

Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://fb.me/react-uselayouteffect-ssr for common fixes.

主要是因為 useLayoutEffect 不會在 Server Side 執行,這時候就可以使用 useSafeLayoutEffect 來解決這個問題。

useSafeLayoutEffect 的實作,概念上很簡單就是將 useLayoutEffect 在 Server Side 的時候,改用 useEffect 來執行。

import {useLayoutEffect, useEffect} from 'react';

const useSafeLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;

useComposedRefs

useComposedRefs 通常是用來合併多個 ref, 而這在 Design System 中是很常見的。

例如有時後我們的需要同時控制組件內部某個元素,並且也能夠讓外部開發者也能控制這個元素。這時候就可以使用 useComposedRefs 來解決這個問題。

舉例來說:

當這個組件 mounted (渲染完成) 的時候,自動 focus 到輸入框上。同時,如果也希望讓其他使用者可以拿到輸入框的值,這時候就可以使用 useComposedRefs 來解決這個問題。

import React, { forwardRef, useEffect, useRef } from 'react';
import { useComposedRefs } from './compose-refs';

const FocusableInput = forwardRef((props, externalRef) => {
  const internalRef = useRef();

  const composedRef = useComposedRefs(externalRef, internalRef);

  useEffect(() => {
    if (internalRef.current) {
      internalRef.current.focus();
    }
  }, []);

  return <input ref={composedRef} {...props} />;
});

export default () => {
  const inputRef = useRef(null);

  const handleButtonClick = () => {
    if (inputRef.current) {
      console.log('輸入框的值是', inputRef.current.value);
    }
  };

  return (
    <div>
      <FocusableInput ref={inputRef} placeholder="Placeholder" />
      <button onClick={handleButtonClick}>Submit</button>
    </div>
  );
};
import React, { useCallback } from 'react';

function assignRef(ref, value) {
  if (ref == null) {
    return;
  }

  if (typeof ref === 'function') {
    ref(value);
  } else {
    Reflect.set(ref, 'current', value);
  }
}

export function useComposedRefs(...refs) {
  return React.useCallback(
    (value) => {
      refs.forEach((ref) => {
        assignRef(ref, value);
      });
    },
    [refs],
  );
}

GIF

CodeSandbox Playground


上一篇
[Day 10] Design System - React Slots (插槽) - 實作
下一篇
[Day 12] Design System - Common Hook (二)
系列文
設計系統 - Design System30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言