useLayoutEffect 알아보기

yejiiha·2021년 6월 25일
1

react native로 작업을 하던 중, TextInput 클릭 시 TextInput width가 줄어들고 cancel 버튼이 생기고 cancel 버튼을 누르면 다시 사라지는 헤더를 구현하고 싶었다.

☝️ 이것 처럼 !

처음에는 이렇게 작성하였다.

type InputProps = {
  width: number;
  isPress: boolean;
};

const SearchWrapper = styled.View`
  flex-direction: row;
  align-items: center;
  width: 100%;
`;

const SearchContainer = styled.View<InputProps>`
  flex-direction: row;
  width: ${(props) =>
    props.isPress ? props.width / 1.3 : props.width / 1.1}px;
  background-color: ${(props) => props.theme.theme.formColor};
  padding: 6px 10px;
  border-radius: 10px;
`;

const SearchInput = styled.TextInput`
  color: ${(props) => props.theme.theme.textColor};
  width: 100%;
  margin-left: 10px;
`;

function Search() {
  const SearchBox = () => (
    <SearchWrapper>
      <SearchContainer width={width} isPress={isPress}>
        <Ionicons name="search" size={24} color={theme.theme.darkGray} />
        <SearchInput
          placeholder="Search"
          autoCapitalize="none"
          returnKeyLabel="Search"
          returnKeyType="search"
          autoCorrect={false}
          onChangeText={(text) => setValue("keyword", text)}
          onSubmitEditing={handleSubmit(onValid)}
          onFocus={() => setIsPress(!isPress)}
        />
      </SearchContainer>

      {isPress ? (
        <CancelContainer
          onPress={() => {
            reset({ keyword: "" });
            setIsPress(!isPress);
          }}
        >
          <Text>Cancel</Text>
        </CancelContainer>
      ) : null}
    </SearchWrapper>
  );

  useEffect(() => {
    navigation.setOptions({
      headerTitle: SearchBox,
    });
  }, []);
}

이렇게 작성하니 console.log(isPress); 했을 때 isPress의 값은 토글되지만 css에는 변동이 없었다.

구글링을 하다가 useLayoutEffect를 사용한 케이스를 보게됐다 !
바로 적용해봤더니 해결 ~!

  useLayoutEffect(() => {
    navigation.setOptions({
      headerTitle: SearchBox,
    });
  }, [isPress]);

❓ useEffect와 useLayoutEffect의 차이점

useEffect

렌더가 화면에 그려진 후 비동기적으로 실행

참고
useEffect를 사용하는 경우, DOM의 레이아웃 배치와 화면이 업데이트 된 후 이펙트 함수를 호출한다.

  1. 컴포넌트 렌더링
  2. 화면 update
  3. useEffect 실행

사용 경우

✅ 일부 상태를 즉시 발생할 필요가 없을 경우
✅ 페이지에 시각적으로 영향을 주지 않는 무언가를 동기화 할 경우
✅ 이벤트 핸들러를 설정하는 경우
✅ 모달 상자가 나타나거나 사라질 때 일부 상태를 재설정하는 경우

useLayoutEffect

렌더링 후 화면이 업데이트 되기 전에 동기적으로 실행

참고

  • useLayoutEffect를 사용하는 경우, 브라우저가 화면에 DOM을 그리기 전에 이펙트를 수행한다.
  • 모든 DOM 변경 후에 동기적으로 발생합니다
  1. 컴포넌트 렌더링
  2. useLayoutEffect 실행
  3. 화면 update

사용 경우

✅ 상태가 업데이트 될 때 요소가 깜박이는 경우
✅ DOM을 변경하려는 경우
이 둘의 가장 큰 차이점은 렌더링 시점에 있다.
✅ DOM에서 레이아웃을 읽고 동기적으로 리렌더링하는 경우

=> 보통의 경우에는 useEffect를 먼저 사용하되, 만약 사용자가 알아차리는 DOM 변경을 하게 될 경우(ex. 화면 깜빡임)는 useLayoutEffect를 써야겠다!

참고

https://hyojin96.tistory.com/entry/%F0%9F%8D%80-useEffect-VS-useLayoutEffect-%F0%9F%8D%80
https://merrily-code.tistory.com/46
https://velog.io/@ziyoonee/useLayoutEffect

profile
Frontend Developer

0개의 댓글