我正在尝试为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(...):只能更新已安装的组件。”是否还有另一种将内联风格改变为儿童的“反应方式”?
答案 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.props
和this.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);