React 路由器 v4 渲染方法重构
React router v4 render method refactor
我有一个运行良好的组件。但我想更改代码,以便
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;
您可以通过对 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 with the important sections being Assignment without declaration and 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 确实简要提到了如何处理大写字母(强调我的):
"JSX 标签的第一部分决定了 React 元素的类型。
大写类型表示 JSX 标签指的是 React 组件。 这些标签被编译成对命名变量的直接引用,因此如果您使用 JSX <Foo />
表达式,Foo
必须在范围内。"
还有 User-Defined Components Must Be Capitalized 部分:
"当元素类型以小写字母开头时,它指的是一个内置组件,如 <div>
或 <span>
并导致字符串 'div'
或 'span'
传递给 React.createElement
。以大写字母开头的类型,如 <Foo />
编译为 React.createElement(Foo)
,并对应于 JavaScript 文件中定义或导入的组件。
我们建议用大写字母命名组件。如果您确实有一个以小写字母开头的组件,请在将其用于 JSX 之前将其分配给大写变量。"
上面的 link 继续显示一些有用的示例。
我有一个运行良好的组件。但我想更改代码,以便
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;
您可以通过对 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 with the important sections being Assignment without declaration and 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 确实简要提到了如何处理大写字母(强调我的):
"JSX 标签的第一部分决定了 React 元素的类型。
大写类型表示 JSX 标签指的是 React 组件。 这些标签被编译成对命名变量的直接引用,因此如果您使用 JSX <Foo />
表达式,Foo
必须在范围内。"
还有 User-Defined Components Must Be Capitalized 部分:
"当元素类型以小写字母开头时,它指的是一个内置组件,如 <div>
或 <span>
并导致字符串 'div'
或 'span'
传递给 React.createElement
。以大写字母开头的类型,如 <Foo />
编译为 React.createElement(Foo)
,并对应于 JavaScript 文件中定义或导入的组件。
我们建议用大写字母命名组件。如果您确实有一个以小写字母开头的组件,请在将其用于 JSX 之前将其分配给大写变量。"
上面的 link 继续显示一些有用的示例。