【问题标题】:React.js: Refs are not available on initial renderReact.js:初始渲染时引用不可用
【发布时间】: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)。

【问题讨论】:

    标签: javascript layout reactjs


    【解决方案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/

    【讨论】:

    • 这看起来确实很老套。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-17
    相关资源
    最近更新 更多