useRef를 통한 렌더링 관리

깡스·2023년 6월 1일
0

지금 진행중인 포트폴리오 생성 사이트는, 포트폴리오를 생성하기 위해 여러 템플릿의 조합으로 하나의 포트폴리오가 만들어 집니다.

이 템플릿은 각각 템플릿에 맞는 정보를 입력할 수 있게 구성되어 있는데, 최종적으로 포트폴리오를 생성하기 위해서는 템플릿의 데이터를 모두 모아 최상단에서 관리할 필요가 있습니다.

그러나 최상단에서 useState를 통해 데이터를 관리하게 되면, 템플릿의 데이터가 변경될 때마다 너무나 많은 요소들에서 re-rendering이 발생하게 됩니다.

이러한 문제점을 해결하고자, 최상위에서 데이터를 수집할 때, re-rendering이 발생하지 않도록 처리하려 합니다.


useRef

이 현상을 해결하기 위해 mutable한 값을 관리할 수 있는 hook, useRef를 이용해 데이터를 관리하려 합니다.

먼저 useRefuseState와 달리 값이 변경되어도 render를 유발하지 않으며, 일반 변수와 달리, state가 변경되어도 값이 그대로 유지됩니다.

const portfolio = useRef({
	header: {
      title:'Portfolio Creator'
    },
  	section: [...data]
})

위와 같은 형태로 데이터를 모아줍니다.

Setter, Getter

portfolio를 관리하기 위한 settergetter를 만들어 줍니다.

// getter
const getPortfolio = useCallback(() => portfolio.current, [])

// setter
const setPortfolio = useCallback((callback) => {
  portfolio.current = callback(portfolio.current);
}, []);

위 함수를 통해 portfolio에 접근할 수 있게 되었습니다.

Context

그런데 데이터를 모으고 있는 최상위 컴포넌트를 제외한 다른 컴포넌트에서 portfolio의 데이터를 수정하거나 필요한 상황이 존재합니다.

다른 컴포넌트에서는 settergetter에 접근할 수 없기에, 최상위 컴포넌트를 Context로 만들어 다른 컴포넌트에서 settergetter에 접근할 수 있도록 해줍니다.

// index.page.js
const CreateContext = createContext(null)

export const Create = ({children}) => {
  const portfolio = useRef({})
  
  const getPortfolio = () => {}
  const setPortfolio = () => {}
  // ... 생략
  
  return (
    <CreateContext.Provider value={{ getPortfolio, setPortfolio }}>
      {children}
    </CreateContext.Provider>
  )
}

export const useCreateContext = () => {
  return useContext(CreateContext);
}

위와 같은 구성을 통해 다른 컴포넌트에서 useCreateContext를 통해 접근할 수 있게 되었습니다.

Request Rendering

위 과정을 통해 re-rendering없이 데이터를 관리할 수 있게 되었습니다.

그렇지만 템플릿을 추가하는 등, re-rendering을 발생시켜 화면 구성의 변경이 필요한 상황도 있습니다.
이러한 상황에 대응하기 위해, requestRender라는 함수를 통해 고의적으로 re-rendering을 발생시킬 수 있게 하려 합니다.

// index.page.js
export const Create = ({children}) => {
  // ... 생략
  const [, setRenderHash] = useState('')
  
  const requestRender = useCallback(() => {
    setRenderHash(JSON.stringify(portfolio.current))
  }, [])
  
  return (
    <CreateContext.Provider value={{ getPortfolio, setPortfolio, requestRender }}>
      {children}
    </CreateContext.Provider>
  )
}

위와 같이 portfolio를 해쉬값으로 변환해, 템플릿이 추가되는 등 해쉬값에 변화가 있으면 re-rendering을 발생시키는 함수를 만들었습니다.


위 과정을 통해 re-rendering없이 최상단에서 템플릿의 데이터들을 취합할 수 있게 되었습니다.
그렇지만 이런 구조가 올바른 방법인지에 대해서는 좀 더 고민할 여지가 있을 것 같습니다.

0개의 댓글