code

componentDidMount가 참조 콜백 전에 호출 됨

codestyles 2020. 11. 11. 20:12
반응형

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가있는 자식을 다른 구성 요소에 전달하면이 구성 요소가 시간 내에 ref를 첨부하지 못하게하는 작업을 수행 할 수 있습니다.

For example, maybe it’s not returning the child from render(), and instead is calling ReactDOM.render() in a lifecycle hook. You can find an example of this here. In that example, we render:

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

But MyModal performs a ReactDOM.render() call in its componentDidUpdate lifecycle method:

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

render() {
  return null;
}

Since React 16, such top-level render calls during a lifecycle will be delayed until lifecycles have run for the whole tree. This would explain why you’re not seeing the refs attached in time.

The solution to this problem is to use portals instead of nested ReactDOM.render calls:

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

This way our <div> with a ref is actually included in the render output.

So if you encounter this issue, you need to verify there’s nothing between your component and the ref that might delay rendering children.

Don't use setState to store refs

Make sure you are not using setState to store the ref in ref callback, as it's asynchronous and before it's "finished", componentDidMount will be executed first.


Still an Issue?

If none of the tips above help, file an issue in React and we will take a look.


A different observation of the problem.

I've realised that the issue only occurred while in development mode. After more investigation, I found that disabling react-hot-loader in my Webpack config prevents this problem.

I am using

  • "react-hot-loader": "3.1.3"
  • "webpack": "4.10.2",

And it's an electron app.

My partial Webpack development config

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'
  ],
  ...
})

It became suspicious when I saw that using inline function in render () was working, but using a bound method was crashing.

Works in any case

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

Crash with react-hot-loader (ref is undefined in componentDidMount)

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

  inputRef (input) {
    this.inputField = input
  }

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

To be honest, hot reload has often been problematic to get "right". With dev tools updating fast, every project has a different config. Maybe my particular config could be fixed. I'll let you know here if that's the case.


In componentDidMount, can you find your ref element (div.drawer) in the browser DOM? If not, you can't have its reference. Since the problem is found in another, larger code, the reason could be that ref element (div.drawer) is not rendered.

참고URL : https://stackoverflow.com/questions/44074747/componentdidmount-called-before-ref-callback

반응형