React.js:初始渲染时引用不可用

Posted

技术标签:

【中文标题】React.js:初始渲染时引用不可用【英文标题】:React.js: Refs are not available on initial render 【发布时间】:2014-04-09 21:44:00 【问题描述】:

我想在组件的根 DOM 元素中间放置一个圆圈:

var App = React.createClass(
    render: function() 
        return <svg ref="svg">
            <circle r="9" cx=this.centerX() cy="15"/>
        </svg>;
    ,
    centerX: function() 
        var svg = this.refs.svg.getDOMNode();
        return svg.offsetLeft + Math.round(svg.offsetWidth / 2);
    
);

http://jsfiddle.net/NV/94tCQ/

鸡和蛋的问题发生在这里:this.refs 在第一次渲染时未定义。解决这个问题的最佳方法是什么?我不希望引用外部 DOM 节点(例如 document.body)。

【问题讨论】:

【参考方案1】:

不是refs 没有定义,而是您在尝试生成 DOM 的同时尝试访问它。 this.refs.svg.getDOMNode 不会返回任何内容,因为该组件在 render 中没有真正的 DOM 表示。

为了保持更多的 React-y,我会将 cx 移动到组件的状态,并在元素渲染到 DOM 后更新它:

var App = React.createClass(
    componentDidMount: function() 
        var svg = this.refs.svg.getDOMNode();
        this.setState(
            cx: svg.offsetLeft + Math.round(svg.offsetWidth / 2)
        );
    ,
    getInitialState: 
        return 
            cx: 0
        ;
    ,
    render: function() 
        return (
            <svg ref="svg">
                <circle r="9" cx=this.state.cx cy="15" />
            </svg>
        );
    
);

【讨论】:

当然,如果您知道 svg 元素的尺寸,您还可以计算渲染中的正确中心,以避免必须从 DOM 中读取。在这种情况下它不会特别明显,但为了性能,最好避免从 DOM 读取并尽可能地重新渲染。 @BenAlpert 好点。尽管在这种情况下,代码引用了offsetLeft,它是相对于 DOM 节点最近定位的父节点的。在将 offsetParent 和此元素都渲染到 DOM 之前,不可能获得该数字。这在 CSS 中可能会更好地解决,但考虑到原始帖子中的代码,这似乎是最合适的。 我完全同意。我的评论主要针对原始海报,作为可选的增强功能。【参考方案2】:

解决此问题的一种巧妙方法是,当它尚未插入 DOM 时返回一个虚拟值,当它插入时(使用 componentDidMount)然后重新绘制元素。

    centerX: function() 
        if (!this.refs || !this.refs.svg) 
            return 0;
        
        var svg = this.refs.svg.getDOMNode();
        return svg.offsetLeft + Math.round(svg.offsetWidth / 2);
    ,
    componentDidMount: function() 
        this.forceUpdate();
    

http://jsfiddle.net/vjeux/94tCQ/4/

【讨论】:

这看起来确实很老套。 :)

以上是关于React.js:初始渲染时引用不可用的主要内容,如果未能解决你的问题,请参考以下文章

组件渲染时Vue JS计算属性尚不可用

react.js在服务器端渲染有啥好处?渲染是怎么个流程

Gatsby:在使用带有 JavaScript 的 Bootstrap 组件构建项目时,服务器端渲染期间“文档”不可用

属性初始化程序在 'self' 可用之前运行

Visual Studio2012 添加服务引用时,生成基于任务操作不可用原因

由于初始化尚未完成,服务不可用