JSX 中道具的顺序重要吗?
Is the ordering of props in JSX important?
如果 o
对象包含 key/value 对:foo: 'bar'
我可以依赖这些结果吗?:
// foo will be 'bar'
<MyComponent
foo='should not override'
{...o}
/>
// foo will be 'overridden'
<MyComponent
{...o}
foo='overridden'
/>
换句话说,使用 spread 运算符时属性的顺序是否重要?
是的,是的。它的工作原理与您的示例完全一样
你的例子翻译成:
// foo will be 'bar'
<MyComponent
{/* ...other 'o' keys/values...*/}
foo='should not override'
{/* ...other 'o' keys/values...*/}
foo='bar'
/>
// foo will be 'overridden'
<MyComponent
foo='bar'
{/* ...other 'o' keys/values...*/}
foo='overridden'
{/* ...other 'o' keys/values...*/}
/>
因此,它总是覆盖最后一个
查看这个沙盒证明:
https://codesandbox.io/s/Q1GMx9KM9
如您所见,它的行为与您在问题中提出的理论完全一致。
编辑
所以片段:
class MyComponent extends React.Component {
render() {
return <div>{this.props.foo}</div>
}
}
const styles = {
fontFamily: 'sans-serif',
textAlign: 'center',
};
const o = { foo: 'bar' };
const App = () =>
<div style={styles}>
<h2>Spreading after explicit property</h2>
<MyComponent foo="will be overriden" {...o} />
<h2>Spreading before explicit property</h2>
<MyComponent {...o} foo="was overriden" />
</div>;
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
是的,顺序很重要。确切的原因是 Babel 如何转换 JSX。您可以在 Babel REPL:
中看到
<MyComponent foo="should not override" {...o}>
</MyComponent>
变为:
React.createElement(MyComponent, _extends({ foo: "overridden" }, o));
其中 _extends
只是 Object.assign
,或者如果浏览器不支持它,_extends
在功能上是相同的。根据 MDN 文档:
Properties in the target object will be overwritten by properties in the sources if they have the same key. Later sources' properties will similarly overwrite earlier ones.
(重点是我的)。因此,当使用 Object.assign
将 props 传递给组件时,目标是 { foo: "overridden" }
,源是 o
。由于 foo
存在于目标和源中,因此目标中的 foo
被覆盖。这也适用于:
<MyComponent {...o} foo="overridden">
</MyComponent>
在这里,JSX 被转译为相反的:
React.createElement(MyComponent, _extends({}, o, { foo: "overriden" }));
有点不同,因为这里的目标是一个空对象,但是引用 MDN 的后半部分适用。这里的来源是 o
和 { foo: "overridden" }
。由于 foo
存在于两个来源中,因此来源 { foo: "overridden" }
中的 foo
会覆盖 o
中的 foo
。
如果 o
对象包含 key/value 对:foo: 'bar'
我可以依赖这些结果吗?:
// foo will be 'bar'
<MyComponent
foo='should not override'
{...o}
/>
// foo will be 'overridden'
<MyComponent
{...o}
foo='overridden'
/>
换句话说,使用 spread 运算符时属性的顺序是否重要?
是的,是的。它的工作原理与您的示例完全一样
你的例子翻译成:
// foo will be 'bar'
<MyComponent
{/* ...other 'o' keys/values...*/}
foo='should not override'
{/* ...other 'o' keys/values...*/}
foo='bar'
/>
// foo will be 'overridden'
<MyComponent
foo='bar'
{/* ...other 'o' keys/values...*/}
foo='overridden'
{/* ...other 'o' keys/values...*/}
/>
因此,它总是覆盖最后一个
查看这个沙盒证明:
https://codesandbox.io/s/Q1GMx9KM9
如您所见,它的行为与您在问题中提出的理论完全一致。
编辑 所以片段:
class MyComponent extends React.Component {
render() {
return <div>{this.props.foo}</div>
}
}
const styles = {
fontFamily: 'sans-serif',
textAlign: 'center',
};
const o = { foo: 'bar' };
const App = () =>
<div style={styles}>
<h2>Spreading after explicit property</h2>
<MyComponent foo="will be overriden" {...o} />
<h2>Spreading before explicit property</h2>
<MyComponent {...o} foo="was overriden" />
</div>;
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
是的,顺序很重要。确切的原因是 Babel 如何转换 JSX。您可以在 Babel REPL:
中看到<MyComponent foo="should not override" {...o}>
</MyComponent>
变为:
React.createElement(MyComponent, _extends({ foo: "overridden" }, o));
其中 _extends
只是 Object.assign
,或者如果浏览器不支持它,_extends
在功能上是相同的。根据 MDN 文档:
Properties in the target object will be overwritten by properties in the sources if they have the same key. Later sources' properties will similarly overwrite earlier ones.
(重点是我的)。因此,当使用 Object.assign
将 props 传递给组件时,目标是 { foo: "overridden" }
,源是 o
。由于 foo
存在于目标和源中,因此目标中的 foo
被覆盖。这也适用于:
<MyComponent {...o} foo="overridden">
</MyComponent>
在这里,JSX 被转译为相反的:
React.createElement(MyComponent, _extends({}, o, { foo: "overriden" }));
有点不同,因为这里的目标是一个空对象,但是引用 MDN 的后半部分适用。这里的来源是 o
和 { foo: "overridden" }
。由于 foo
存在于两个来源中,因此来源 { foo: "overridden" }
中的 foo
会覆盖 o
中的 foo
。