设置内联式的儿童风格

时间:2014-06-29 09:19:03

标签: javascript reactjs

我正在尝试为React中的子项设置一些内联样式。我有这个实际上有用,有点:

var App = React.createClass({
  render: function() {
    var children = React.Children.map(this.props.children, function(child, i) {
      child.props.style.width = '100px'
    })
    return (
      <div>{children}</div>
    )
  }
})

但是,如果我在状态发生变化时尝试更改样式,样式将保持不变。尝试这样的事情时,你可以很容易地看到这一点:(小提琴:http://jsfiddle.net/9UvWL/

var World = React.createClass({
    getInitialState: function() {
        return { width: 0 }
    },
    componentDidMount: function() {
        this.setState({ width: 100 })
    },
    componentDidUpdate: function() {
        console.log(this.getDOMNode().innerHTML);
    },
    render: function() {
        var width
        var children = React.Children.map(this.props.children, function(child, i) {
            width = i*this.state.width
            console.log('Setting width: '+width);
            child.props.style = {width: (i*this.state.width)+'px'}
            return child
        }, this)
        return <div>{children}</div>
    }
 })

var Hello = React.createClass({
    render: function() {
        return (
            <World>
                <div>1</div>
                <div>1</div>
            </World>
        )
    }
})

React.renderComponent(<Hello />, document.body);

它将记录宽度已更改,但props.style未按预期工作。使用child.setProps()会抛出“不变违规:replaceProps(...):只能更新已安装的组件。”是否还有另一种将内联风格改变为儿童的“反应方式”?

2 个答案:

答案 0 :(得分:5)

您正在直接修改每个子项的props对象,这会绕过React的更新机制的一部分。我们很快就会做到这一点。

在这种情况下,您希望在cloneWithProps组件的渲染功能中使用World

var children = React.Children.map(this.props.children, function(child, i) {
    width = i*this.state.width;
    console.log('Setting width: '+width);
    return React.addons.cloneWithProps(child, {style: {width: width + 'px'}})
}, this)
return <div>{children}</div>

cloneWithProps创建组件的新副本并合并其他道具。您应该使用此模式来确保您提供React所需的所有提示,以了解何时更新。

以下是您工作的示例:http://jsfiddle.net/zpao/Tc5Qd/

答案 1 :(得分:2)

在“只能更新已安装的组件”检查之后,还有另一个more descriptive error message

  invariant(
    this._mountDepth === 0,
    'replaceProps(...): You called `setProps` or `replaceProps` on a ' +
    'component with a parent. This is an anti-pattern since props will ' +
    'get reactively updated when rendered. Instead, change the owner\'s ' +
    '`render` method to pass the correct value as props to the component ' +
    'where it is created.'
  );

逻辑来自与更新DOM节点不同的视角。当需要更改DOM节点时,通常的方法是获取对DOM节点的引用,然后设置其属性。使用React,渲染方法只返回具有正确属性集的新React组件,而不是更新特定节点,然后后端代码确定要更新的DOM节点。

当正常的DOM代码中出现错误的东西时,很难知道问题出在哪里,因为任何代码都可以更新DOM节点。

当代码被安排到React中的渲染方法时,渲染方法总是接受this.propsthis.state并返回完整渲染的完整组件。然后,如果某些内容未正确呈现,则始终可以查看render方法来查找问题,因为这是渲染发生的唯一位置。 (无论是第一次渲染还是第二次渲染,这都有效,因此首次渲染组件和更新组件时无需区分。)

因此,围绕您所描述的问题的方法是将关于渲染div的逻辑移动到创建div的render方法,而不是在不同组件的render方法中。像这样:

var World = React.createClass({
    render: function() {
        return <div>{this.props.children}</div>;
    }
 });

var Hello = React.createClass({
    getInitialState: function() {
        return { width: 0 };
    },
    componentDidMount: function() {
        this.setState({ width: 100 });
    },
    render: function() {
        var children = ["a", "b", "c"].map(function(content, i) {
            return (
                <div style={{ width: i * this.state.width }}>
                    {content}
                </div>
            );
        }, this);

        return (
            <World>
                {children}
            </World>
        )
    }
});

React.renderComponent(<Hello />, document.body);

http://jsfiddle.net/kN4DV/2/