문제
ref
인라인 함수 정의를 사용하여 반응 을 설정하고 있습니다.
render = () => {
return (
<div className="drawer" ref={drawer => this.drawerRef = drawer}>
그런 다음 componentDidMount
DOM 참조가 설정되지 않았습니다.
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
또는 componentDidUpdate
hooks 이전에 설정되도록 보장합니다 . 그러나 실제로 렌더링 된 어린이에게만 해당 됩니다 .
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
를 저장 하는 데 사용하지 마십시오.
setState
ref 콜백에 ref를 저장하는 데 사용 하고 있지 않은지 확인하십시오. 이는 비동기적이고 “완료”되기 전에 componentDidMount
먼저 실행될 것입니다.
여전히 문제가 있습니까?
위의 팁 중 어느 것도 도움이되지 않는 경우 React에 문제를 제출하면 살펴 보겠습니다.
답변
문제에 대한 다른 관찰.
이 문제는 개발 모드에서만 발생한다는 것을 깨달았습니다. 더 많은 조사 결과, react-hot-loader
Webpack 구성에서 비활성화 하면이 문제가 방지 된다는 것을 알았습니다 .
나는 사용하고있다
- “반응 핫 로더”: “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)
}