[javascript] componentDidMount가 참조 콜백 전에 호출 됨

문제

ref인라인 함수 정의를 사용하여 반응 을 설정하고 있습니다.

render = () => {
    return (
        <div className="drawer" ref={drawer => this.drawerRef = drawer}>

그런 다음 componentDidMountDOM 참조가 설정되지 않았습니다.

componentDidMount = () => {
    // this.drawerRef is not defined

내 이해는 ref콜백이 마운트 중에 실행되어야한다는 것입니다. 그러나 console.log문을 추가 하면 ref 콜백 함수 componentDidMount가 호출 되기 전에 호출됩니다.

내가 예를 들어 검토 한 다른 코드 샘플 이 토론 GitHub의에서이 같은 가정을 나타낸다는 componentDidMount호출 할 필요가 이후 어떤 ref정의 콜백 render이도있어, 대화에 명시된

그래서 모든 ref 콜백이 실행 된 후 componentDidMount가 시작됩니까?

예.

반응 15.4.1을 사용하고 있습니다.

내가 시도한 다른 것

ref함수가 호출되고 있는지 확인하기 위해 클래스에서 다음과 같이 정의 해 보았습니다.

setDrawerRef = (drawer) => {
  this.drawerRef = drawer;
}

그런 다음 render

<div className="drawer" ref={this.setDrawerRef}>

이 경우 콘솔 로깅은 콜백이 실제로 호출되고 계시 componentDidMount



답변

짧은 대답:

React는 ref가 componentDidMount또는 componentDidUpdatehooks 이전에 설정되도록 보장합니다 . 그러나 실제로 렌더링 된 어린이에게만 해당 됩니다 .

componentDidMount() {
  // can use any refs here
}

componentDidUpdate() {
  // can use any refs here
}

render() {
  // as long as those refs were rendered!
  return <div ref={/* ... */} />;
}

이것이 “React는 이러한 후크가 실행되기 전에 항상 모든 참조를 설정 합니다 “를 의미하지는 않습니다 .
참조 가 설정 되지 않은 몇 가지 예를 살펴 보겠습니다 .


렌더링되지 않은 요소에 대한 참조가 설정되지 않습니다.

React는 render에서 실제로 반환 한 요소에 대해서만 ref 콜백을 호출 합니다.

이것은 코드가

render() {
  if (this.state.isLoading) {
    return <h1>Loading</h1>;
  }

  return <div ref={this._setRef} />;
}

그리고 처음 this.state.isLoading입니다 true당신이해야 하지 기대 this._setRef하기 전에 호출 할 componentDidMount.

이것은 의미가있을 것입니다 : 만약 당신의 첫 번째 렌더가 반환 되었다면 <h1>Loading</h1>React가 어떤 다른 조건에서 ref가 첨부되어야하는 다른 것을 반환한다는 것을 알 수있는 방법이 없습니다. 또한이 없다 :에 심판 설정하는 것도<div> 때문에 요소가 작성되지 않았습니다 render()방법은 렌더링되지 않을 것이라고 말했다는.

따라서이 예에서는 만 componentDidMount실행됩니다. 그러나 경우 this.state.loading에 변경false , 당신은 볼 것이다 this._setRef첫째 부착 한 다음 componentDidUpdate실행됩니다.


다른 구성 요소에주의

참고 것을 당신이 다른 구성 요소에 이르기까지 심판 어린이를 전달하는 경우 가 방지 렌더링 (그리고 문제로 인해) 뭔가를하고있는 기회가있다.

예를 들면 다음과 같습니다.

<MyPanel>
  <div ref={this.setRef} />
</MyPanel>

출력에 MyPanel포함하지 않으면 작동 하지 않습니다 props.children.

function MyPanel(props) {
  // ignore props.children
  return <h1>Oops, no refs for you today!</h1>;
}

다시 말하지만, 그것은 버그가 아닙니다 : DOM 요소가 생성되지 않았기 때문에 React가 ref를 설정할 아무것도 없을 것입니다 .


참조가 중첩으로 전달되는 경우 수명주기 전에 설정되지 않습니다. ReactDOM.render()

이전 섹션과 마찬가지로 ref가있는 자식을 다른 구성 요소에 전달하면이 구성 요소가 시간 내에 참조를 첨부하지 못하게하는 작업을 수행 할 수 있습니다.

예를 들어에서 자식을 반환하지 render()않고 대신 ReactDOM.render()수명주기 후크를 호출 할 수 있습니다. 여기 에서 이에 대한 예를 찾을 수 있습니다 . 이 예에서는 다음을 렌더링합니다.

<MyModal>
  <div ref={this.setRef} />
</MyModal>

그러나 MyModal수행 ReactDOM.render()에 호출 componentDidUpdate 수명주기 방법 :

componentDidUpdate() {
  ReactDOM.render(this.props.children, this.targetEl);
}

render() {
  return null;
}

React 16 이후 로 수명주기 동안 이러한 최상위 렌더링 호출은 전체 트리에 대해 수명주기가 실행될 때까지 지연됩니다 . 이것은 왜 당신이 시간에 첨부 된 심판을 보지 못하는지 설명 할 것입니다.

이 문제에 대한 해결책 은 중첩 된 호출 대신 포털 을 사용하는
것입니다 ReactDOM.render.

render() {
  return ReactDOM.createPortal(this.props.children, this.targetEl);
}

이렇게 <div>하면 참조가있는 우리 가 실제로 렌더링 출력에 포함됩니다.

따라서이 문제가 발생하면 구성 요소와 참조 사이에 자식 렌더링을 지연시킬 수있는 요소가 없는지 확인해야합니다.

참조 setState를 저장 하는 데 사용하지 마십시오.

setStateref 콜백에 ref를 저장하는 데 사용 하고 있지 않은지 확인하십시오. 이는 비동기적이고 “완료”되기 전에 componentDidMount먼저 실행될 것입니다.


여전히 문제가 있습니까?

위의 팁 중 어느 것도 도움이되지 않는 경우 React에 문제를 제출하면 살펴 보겠습니다.


답변

문제에 대한 다른 관찰.

이 문제는 개발 모드에서만 발생한다는 것을 깨달았습니다. 더 많은 조사 결과, react-hot-loaderWebpack 구성에서 비활성화 하면이 문제가 방지 된다는 것을 알았습니다 .

나는 사용하고있다

  • “반응 핫 로더”: “3.1.3”
  • “webpack”: “4.10.2”,

그리고 그것은 전자 앱입니다.

내 부분적인 Webpack 개발 구성

const webpack = require('webpack')
const merge = require('webpack-merge')
const baseConfig = require('./webpack.config.base')

module.exports = merge(baseConfig, {

  entry: [
    // REMOVED THIS -> 'react-hot-loader/patch',
    `webpack-hot-middleware/client?path=http://localhost:${port}/__webpack_hmr`,
    '@babel/polyfill',
    './app/index'
  ],
  ...
})

render ()에서 인라인 함수를 사용하는 것이 작동하는 것을 보았을 때 의심 스러웠지만 바운드 메서드를 사용하면 충돌이 발생했습니다.

어떤 경우에도 작동

class MyComponent {
  render () {
    return (
      <input ref={(el) => {this.inputField = el}}/>
    )
  }
}

react-hot-loader와 충돌 (ref는 componentDidMount에서 정의되지 않음)

class MyComponent {
  constructor (props) {
    super(props)
    this.inputRef = this.inputRef.bind(this)
  }

  inputRef (input) {
    this.inputField = input
  }

  render () {
    return (
      <input ref={this.inputRef}/>
    )
  }
}

솔직히 말해서, hot reload는 “올바르게”되기 위해 종종 문제가되었습니다. 개발 도구가 빠르게 업데이트되므로 모든 프로젝트는 다른 구성을 갖습니다. 내 특정 구성이 수정 될 수 있습니다. 이 경우 여기에서 알려 드리겠습니다.


답변

setinterval에서 참조를 사용하는 것과 같이 마운트 해제 된 구성 요소의 참조를 사용하려고하고 구성 요소 마운트 해제 중에 설정된 간격을 지우지 않는 경우에도 문제가 발생할 수 있습니다.

componentDidMount(){
    interval_holder = setInterval(() => {
    this.myref = "something";//accessing ref of a component
    }, 2000);
  }

예를 들어 항상 명확한 간격,

componentWillUnmount(){
    clearInterval(interval_holder)
}


답변