Javascript 在ref回调之前调用componentDidMount
问题 我正在使用内联函数定义设置reactJavascript 在ref回调之前调用componentDidMount,javascript,reactjs,Javascript,Reactjs,问题 我正在使用内联函数定义设置react render = () => { return ( <div className="drawer" ref={drawer => this.drawerRef = drawer}> 我的理解是ref回调应该在装载期间运行,但是添加console.log语句会显示componentDidMount在调用ref回调函数之前调用 我在github上看到的其他代码示例表明了相同的假设,componentDidM
render = () => {
return (
<div className="drawer" ref={drawer => this.drawerRef = drawer}>
我的理解是ref
回调应该在装载期间运行,但是添加console.log
语句会显示componentDidMount
在调用ref回调函数之前调用
我在github上看到的其他代码示例表明了相同的假设,componentDidMount
应该在render
中定义的任何ref
回调之后调用,这是偶数
因此,在所有ref回调完成后,componentDidMount将被触发
被处决了
对
我使用的是react 15.4.1
我试过的其他东西
为了验证调用了ref
函数,我尝试在类中定义它
setDrawerRef = (drawer) => {
this.drawerRef = drawer;
}
然后在渲染中
<div className="drawer" ref={this.setDrawerRef}>
在这种情况下,控制台日志显示回调确实在componentDidMount之后被调用
React保证在componentDidMount
或componentDidUpdate
挂钩之前设置引用。但仅适用于实际渲染的儿童
componentDidMount() {
// can use any refs here
}
componentDidUpdate() {
// can use any refs here
}
render() {
// as long as those refs were rendered!
return <div ref={/* ... */} />;
}
如果MyPanel
的输出中不包含props.children
,则无法工作:
function MyPanel(props) {
// ignore props.children
return <h1>Oops, no refs for you today!</h1>;
}
但是MyModal
在其componentdiddupdate
生命周期方法中执行ReactDOM.render()
调用:
componentDidUpdate() {
ReactDOM.render(this.props.children, this.targetEl);
}
render() {
return null;
}
自React 16以来,生命周期中的此类顶级渲染调用将被延迟,直到整个树的生命周期运行为止。这可以解释为什么你没有及时看到裁判
解决此问题的方法是使用
而不是嵌套的ReactDOM.render
调用:
render() {
return ReactDOM.createPortal(this.props.children, this.targetEl);
}
这样,带有ref的
实际上包含在渲染输出中
因此,如果遇到此问题,则需要验证组件和ref之间没有可能延迟渲染子级的内容
不要使用setState
存储引用
确保您没有使用setState
在ref回调中存储ref,因为它是异步的,在“完成”之前,componentDidMount
将首先执行
还是个问题吗?
如果以上提示都没有帮助,请在React中提交一个问题,我们将进行查看 对问题的不同观察 我意识到这个问题只发生在开发模式下。 经过进一步调查,我发现在我的网页配置中禁用
react hot loader
,可以防止这个问题
我正在使用
- “反应热加载程序”:“3.1.3”
- “网页包”:“4.10.2”
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}}/>
)
}
}
类MyComponent{
渲染(){
返回(
{this.inputField=el}}/>
)
}
}
使用react热加载程序崩溃(componentDidMount中未定义ref)
类MyComponent{
建造师(道具){
超级(道具)
this.inputRef=this.inputRef.bind(this)
}
inputRef(输入){
this.inputField=输入
}
渲染(){
返回(
)
}
}
老实说,热重新加载常常是“正确”的问题。随着开发工具的快速更新,每个项目都有不同的配置。
也许我的特定配置可以修复。如果是这样的话,我会在这里告诉您。当您尝试使用未安装组件的ref时,也会出现问题,就像在setinterval中使用ref一样,并且在组件卸载期间不清除set interval
componentDidMount(){
interval_holder = setInterval(() => {
this.myref = "something";//accessing ref of a component
}, 2000);
}
始终清除间隔,例如
componentWillUnmount(){
clearInterval(interval_holder)
}
我可能错了,但当您使用arrow函数进行渲染方法时,它将从类外的词法范围捕获
this
的值。试着去掉类方法的arrow函数语法,看看它是否有用。@GProst这就是我问题的本质。我将console.log放在两个函数中,componentDidMount首先运行,其次是ref回调。只是有一个类似的问题——对我们来说,基本上,我们在最初的渲染时错过了它,因此需要利用componentDidUpdate
,因为componentDidMount
不是更新的一部分。可能不是您的问题,但认为它可能值得作为一个潜在的解决方案提出。React 16也是如此。文档清楚地说明了ref回调是在componentDidMount或componentDidUpdate生命周期挂钩之前调用的。
但这似乎不是真的:(1.ref箭头声明是:ref={ref=>{this.drawerRef=ref}}
2.甚至在componentDidMount之前调用ref;只有在呈现案例中的div时,才能在初始呈现之后访问ref。因此,您必须能够在下一个级别中访问ref,即,在componentWillReceiveProps中使用this.drawerRef
3。如果您尝试在初始装载之前访问ref,则只能获得未定义的va我也对我的答案进行了编辑,以解释这种情况。请参阅第一节。希望这能有所帮助!嗨@DanAbramov谢谢!不幸的是,当我第一次遇到它时,我无法开发出一个可复制的案例。遗憾的是,我不再从事该项目,并且从那时起就无法重新编写。这个问题已经变得足够流行了hough,我同意这一点,试图找到可复制的案例是关键,因为许多人似乎都遇到了这个问题。我认为在许多情况下,这可能是由于误解造成的。在React 15中,这也可能是由于被吞没的错误造成的(React 16具有更好的错误处理能力,可以防止这种情况发生).当这种情况发生时,我很乐意回顾更多的案例,所以请放心
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'
],
...
})
class MyComponent {
render () {
return (
<input ref={(el) => {this.inputField = el}}/>
)
}
}
class MyComponent {
constructor (props) {
super(props)
this.inputRef = this.inputRef.bind(this)
}
inputRef (input) {
this.inputField = input
}
render () {
return (
<input ref={this.inputRef}/>
)
}
}
componentDidMount(){
interval_holder = setInterval(() => {
this.myref = "something";//accessing ref of a component
}, 2000);
}
componentWillUnmount(){
clearInterval(interval_holder)
}