• 카테고리

    질문 & 답변
  • 세부 분야

    프론트엔드

  • 해결 여부

    해결됨

[2.4장 다이얼로그 1] 2.4.5 withLayout(풀이) 에 관한 질문입니다.

24.03.08 10:28 작성 조회수 93

1

안녕하세요 선생님 혼자 해보는 과정중에 질문이 있습니다.

import React from "react";
import Backdrop from "../components/Backdrop";
import Dialog from "../components/Dialog";

export const layoutContext = React.createContext({});
layoutContext.displayName = "LayoutContext";

export class Layout extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      dialog: null,
    };
    this.setDialog = this.setDialog.bind(this);
  }

  setDialog(dialog) {
    this.setState({ dialog });
  }

  render() {
    const value = {
      dialog: this.state.dialog,
      setDialog: this.setDialog,
    };
    return (
      <layoutContext.Provider value={value}>
        {this.props.children}
      </layoutContext.Provider>
    );
  }
}

export const DialogContainer = () => (
  <layoutContext.Consumer>
    {({ dialog }) => dialog && <Backdrop>{dialog}</Backdrop>}
  </layoutContext.Consumer>
);

export const withLayout = (WrappedComponent) => {
  const WithLayout = (props) => (
    <layoutContext.Consumer>
      {({ dialog, setDialog }) => {
        const openDialog = () => {
          console.log("openDialog")
          setDialog(<Dialog>hihi</Dialog>);
        };
        const closeDialog = () => {
          setDialog(null);
        };
        const enhancedProps = {
          openDialog,
          closeDialog,
        };

        return (
          <WrappedComponent {...props} {...enhancedProps}></WrappedComponent>
        );
      }}
    </layoutContext.Consumer>
  );
  return WithLayout;
};

withLayout을 만들어서 openDialog, closeDialog를 enhancedProps로 전달을 하였습니다.

import * as MyLayout from "../lib/MyLayout";

const Page = ({ header, children, footer, openDialog }) => (
  <div className="Page">
    <header>{header}</header>
    <main>{children}</main>
    <footer>{footer}</footer>
    <MyLayout.DialogContainer />
    <button onClick={openDialog}>dialog</button>
  </div>
);

export default MyLayout.withLayout(Page);

Page에서 MyLayout.DialogContainer이 기본값이 null인데 button을 추가하여 고차컴포넌트에서 주입받은 openDialog를 사용하여 Dialog를 렌더링하는데 성공하였습니다.

닫기도 해보고싶어서

import * as MyLayout from "../lib/MyLayout";

const Dialog = ({ closeDialog }) => (
  <div className="Dialog">
    <header>header</header>
    <main>main</main>
    <footer>footer</footer>
    <button onClick={closeDialog}>closeDialog</button>
  </div>
);

export default MyLayout.withLayout(Dialog);

Dialog component에 닫기 버튼을 추가하려고 MyLayout.withLayout으로 감싸니

초기화 전에 참조하려 했다는데 이 에러 자체는 이해가 가지만 왜 지금 위 상황이 이 에러에 해당되는 상황인지 이해가 가지 않습니다...

답변 1

답변을 작성해보세요.

1

Dialog.jsx에서 MyLayout 모듈을 가져올 때 참조 오류가 발생하네요

  • Uncaught ReferenceError: can't access lexical declaration 'withLayout' before initialization

순환 참조 오류인데요. 각 모듈이 서로 가져오기를 할경우 발생합니다. 이 경우는

  • MyLayout.jsx에서 Dialog.jsx를 불러오고

  • Dialog.jsx에서 MyLayout.jsx를 불러옴.

이 브라우져가 모듈을 가져올 때 종단점 없이 계속 가져오기를 시도하는데, 이 때 참조 오류를 예외로 발생시키는 현상입니다.

순환 참조는 코드가 많아질수록 발견될 가능성이 많고요. 고려해서 잘 설계하는 게 중요합니다.

관련해 정리한 내용도 참고해주세요.