我有一个运作良好的组件。但我想改变代码,所以
React.createElement(component, { ...props, loggingIn, authenticated })
将使用 JSX 编写。
import React, { PropTypes } from 'react';
import { Route, Redirect } from 'react-router-dom';
const Public = ({ loggingIn, authenticated, component, ...rest }) => (
<Route {...rest} render={(props) => {
if (loggingIn) return <div></div>;
return !authenticated ?
(React.createElement(component, { ...props, loggingIn, authenticated })) :
(<Redirect to="/documents" />);
}} />
);
Public.propTypes = {
loggingIn: PropTypes.bool,
authenticated: PropTypes.bool,
component: PropTypes.func,
};
export default Public;
答案 0 :(得分:1)
只需对Public
组件的参数稍作更改即可完成此操作。
const Public = ({ component: Component, loggingIn, authenticated, ...rest }) => (
我花了一些实验来了解如何捕获组件参数以便将其用作JSX ,因此我使用下面的代码创建了working example on Codepen。 (注意我使用HashRouter
因为BrowserRouter
在Codepen中不起作用。忽略它 - 对解决方案不重要。我还删除了Public
组件中的一些逻辑关注解决方案。在最终的代码中,您当然可以将loggingIn
和authenticated
逻辑添加回Public
组件。)
const {
HashRouter,
Route,
Switch,
Link
} = ReactRouterDOM
const Home = () => (
<span>Home</span>
);
const Another = (props) => (
<div>
<span>Another</span>
<div>Bah: {props.bah}</div>
</div>
);
const NotHome = (props) => {
return (
<div>
<div>Not Home</div>
<div>Logging in: {props.loggingIn}</div>
<div>Authenticated: {props.authenticated}</div>
<div>Other prop: {props.otherProp}</div>
<div>Route props(match.path): {props.match.path}</div>
</div>
);
};
const Public = ({ component: Component, loggingIn, authenticated, ...rest }) => (
<Route {...rest} render={(props) => {
// return (React.createElement(Component, { ...props, loggingIn, authenticated }));
return (<Component {...props} {...rest} loggingIn={loggingIn} authenticated={authenticated} />);
}} />
);
ReactDOM.render((
<HashRouter>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/public">Public</Link></li>
<li><Link to="/another">Another</Link></li>
</ul>
<p>The rendered route component:{' '}
<Switch>
<Route exact path="/" component={Home} />
<Public path="/public" component={NotHome} loggingIn="could be" authenticated="perhaps" otherProp="bar" />
<Public path="/another" component={Another} loggingIn="no..." authenticated="not" bah="baz" />
</Switch>
</p>
</div>
</HashRouter>
), document.getElementById('app'));
我认为理解这一点的关键是将how Babel transforms the JSX看到createElement
,您会注意到:
<Public component={MyComponent} />
变换为:
React.createElement(Public, { component: MyComponent });
基本部分为{ component: MyComponent }
,因此您的参数需要更改。但是等等,这没有多大意义。因为{ component }
的参数与{ component: component }
相同。请参阅MDN docs on destructuring assignment syntax,重要部分为Assignment without declaration和Assigning to new variable names。
所以在我的工作示例中真正发生的唯一事情是变量名现在大写了...... Wat?
深入挖掘,using Babel some more,真正的原因是JSX处理小写和大写组件名称的方式。比较:
console.log(<component />);
// Which is transformed to:
console.log(React.createElement("component", null));
使用:
console.log(<Component />);
// Transformed to:
console.log(React.createElement(Component, null));
您需要使用大写来获取变量名而不是字符串。 (这导致了另一种解决方案,但这意味着将属性名称大写,这不是标准的,因此我没有提供该解决方案。)
事实上,React JSX In Depth docs简要提到了如何处理大写(强调我的):
&#34; JSX标记的第一部分确定了React元素的类型。
大写类型表示JSX标记指的是React组件。 这些标记被编译成对命名变量的直接引用,因此如果使用JSX <Foo />
表达式,Foo
必须在范围内。&#34;
还有User-Defined Components Must Be Capitalized部分:
&#34;当元素类型以小写字母开头时,它引用内置组件,如<div>
或<span>
,并生成字符串'div'
或{{ 1}}传递给'span'
。以大写字母开头的类型如React.createElement
编译为<Foo />
,并对应于JavaScript文件中定义或导入的组件。
我们建议使用大写字母命名组件。如果你有一个以小写字母开头的组件,在将它用于JSX之前将其分配给大写变量。&#34;
上面的链接继续展示一些有用的例子。