itsource

왜 '약속'일까?console.log가 아닌 React 컴포넌트에서 두 번 호출된 경우

mycopycode 2023. 3. 28. 21:47
반응형

왜 '약속'일까?console.log가 아닌 React 컴포넌트에서 두 번 호출된 경우

다음 컴포넌트의 출력이 매우 혼란스럽습니다.

import { StrictMode } from "react"
import ReactDOM from "react-dom"

function Test(): React.ReactElement {
    console.log('render')
    Promise.resolve()
        .then(() => console.log('then ' + Math.random()))
    return <></>
}

ReactDOM.render(
  <StrictMode>
    <Test />
  </StrictMode>,
  document.getElementById("root")
)

적어도 Chrome 및 Firefox에서는 다음 출력이 생성됩니다.

00:46:30.264 render
00:46:30.267 then 0.5430663800781927
00:46:30.267 then 0.9667426372511254

나는 차라리 같은 수의 메시지를 볼 수 있기를 기대한다.제가 무엇을 빠뜨리고 있나요?

리프로파일: https://codesandbox.io/s/elegant-frost-dmcsl

EDIT: strict 모드가 추가 렌더링으로 이어진다는 것은 알고 있습니다만, 앞에서 설명한 바와 같이 동일한 수의 메시지가 표시됩니다.

EDIT 2: 다음 두 답변 모두 훌륭합니다.@user56reinstatemonica8의 코멘트를 인용하고 싶습니다.

관련: 콘솔 소음에 대한 커뮤니티 피드백

React strict 모드에서는 respect가 렌더링을 여러 번 실행할 수 있으며, 이는 표시되는 내용을 부분적으로 설명할 수 있습니다.

그러나 당신은 그것이 사실인지, 렌더가 여러 호출되었는지, 왜 두 번 인쇄되지 않았는지 정확히 알고 있습니다.

React는 콘솔 방식을 다음과 같이 변경합니다.console.log()경우에 따라서는 로그를 정지합니다.다음은 견적을 제시하겠습니다.

React 17부터 react는 console.log() 등의 콘솔 메서드를 자동으로 변경하여 라이프 사이클 함수에 대한 두 번째 호출 시 로그를 무음화합니다.단, 회피책을 사용할 수 있는 경우에 따라서는 바람직하지 않은 동작이 발생할 수 있습니다.

듣자하니, 그것은 그렇게 하지 않는 것 같다.console.logPromise 콜백에서 호출됩니다.그러나 렌더에서 호출할 때는 그렇게 됩니다.이에 대한 자세한 내용은 @trincot의 답변을 참조하십시오.

strict 모드가 유효하게 되어 있는 경우(개발 모드에서만) 렌더 함수의 두 번째 실행이 있습니다만, 여기서 설명한 바와 같이 React는 패치를 몽키합니다.console메서드(개요)disableLogs();(동기화)가 실행되는 동안 출력되지 않도록 합니다.

코드가 삽입된 것을 Changelog에 나타냅니다.packages/react-reconciler/src/ReactFiberBeginWork.js로그를 일시적으로 억제하려면(코멘트가 표시된 삽입)

  if (__DEV__) {
    ReactCurrentOwner.current = workInProgress;
    setIsRendering(true);
    nextChildren = renderWithHooks(
      current,
      workInProgress,
      render,
      nextProps,
      ref,
      renderExpirationTime,
    );
    if (
      debugRenderPhaseSideEffectsForStrictMode &&
      workInProgress.mode & StrictMode
    ) {
      disableLogs();       // <--
      try {                // <--
        nextChildren = renderWithHooks(
          current,
          workInProgress,
          render,
          nextProps,
          ref,
          renderExpirationTime,
        );
      } finally {          // <--
        reenableLogs();    // <--
      }                    // <--

다음은 실제로 두 번 실행되는 코드 버전입니다.

var i = 0;
var myconsolelog = console.log; // Work around React's monkeypatching 

function Test(): React.ReactElement {
    i++;
    myconsolelog(i + ". render"); // will output twice now!
    Promise.resolve(i)
        .then((i) => console.log(i + ". then " + Math.random()));
    return <></>;
}

이 로그 억제는 정말 잘못된 설계 선택이라고 생각합니다.

혹시 도움이 될지도 모르니까 몽키패치라도 해Object.defineProperties에 대한 변경을 무시합니다.console오브젝트, React DOM의 원숭이 패치를 효과적으로 방지합니다.console.log.

const defineProperties = Object.defineProperties;
Object.defineProperties = function (o, props) {
  return o === console ? o : defineProperties(o, props);
};

반드시 개발 모드로 해 주세요(예를 들어 create-react-app의 경우).process.env.NODE_ENV === 'development'()는, 빌드 )에

언급URL : https://stackoverflow.com/questions/68291908/why-is-promise-then-called-twice-in-a-react-component-but-not-the-console-log

반응형