오늘의 사실 - React에서 렌더링하던 중 원하는 값이 안나왔을 때

React 개발을 하던 중, 상위 컴포넌트가 path를 받아와서 처리해 넘겨주는 부분이 있었습니다.

const Main = () => {
  const [state, setState] = useState(0);
  const [path, setPath] = useState("");

  const selectFile = useCallback(async () => {
    const { filePaths } = await remote.dialog.showOpenDialog();

    if (filePaths.length) {
      setState(1);
      setPath(filePaths[0]);
    }
  }, [setState, setPath]);

  return state ? (
    <>
      <Topbar />
      <SelectedImage path={path} />
    </>
  ) : (
    <>
      <Topbar />
      <div className={style}>
        <div className={innerDiv}>
          <Button color="primary" onClick={selectFile}>
            Select file
          </Button>
        </div>
      </div>
    </>
  );
};

하지만, 이 코드는 문제가 있습니다. 렌더링이 두 번 됩니다! 결론적으로, 맨 처음 path는 공백 문자열이 주어집니다. 리액트 상에선 렌더링이 두 번 돼도 props는 고정인 듯 합니다. 따라서 저 path는 영원히 ''인 거였던 거죠.

아니 그럼, 영원히 path를 받아 올 수 없는 건가요? redux라도 끌어와야 되는거 아닙니까?

아닙니다. 해결법은 단순했습니다.

const Main = () => {
  const [state, setState] = useState(0);
  const [path, setPath] = useState("");

  const selectFile = useCallback(async () => {
    const { filePaths } = await remote.dialog.showOpenDialog();

    if (filePaths.length) {
      setPath(filePaths[0]);
      setState(1);
    }
  }, [setState, setPath]);

  return state ? (
    <>
      <Topbar />
      <SelectedImage path={path} />
    </>
  ) : (
    <>
      <Topbar />
      <div className={style}>
        <div className={innerDiv}>
          <Button color="primary" onClick={selectFile}>
            Select file
          </Button>
        </div>
      </div>
    </>
  );
};

보이시나요? 단순히 setPath()와 setState()의 위치만을 변경했을 뿐입니다. 렌더링이 아주 잘 됩니다!

하… 서순이 이래서 중요하구나 하는 걸 다시 한 번 느끼고 갑니다. 이래서 하스스톤을 많이 했어야

2 Likes

앗, 중요한 걸 깜빡했네요. React + Electron으로 로컬 리소스를 불러오려면 webSecurity: false 설정을 해 주셔야 합니다. 이거 안하고도 할 수 있는 방법 있으면 제보 부탁드립니다 :joy: