[英]Converting stateless React component having arguments to stateful
Inside my React JS project, I am working on the PrivateRoutes
. 在我的React JS项目中,我正在研究
PrivateRoutes
。 I have gone through this example of private routing and authenticating using react-router-dom
. 我已经完成了私有路由和使用
react-router-dom
身份验证的示例。
https://reacttraining.com/react-router/web/example/auth-workflow https://reacttraining.com/react-router/web/example/auth-workflow
According to this documentation, they have created a PrivateRoute
as a stateless component. 根据此文档,他们创建了一个
PrivateRoute
作为无状态组件。
But my requirement is to convert it to stateful React component as I want to connect my PrivateRoute
component to redux store. 但我的要求是将其转换为有状态的React组件,因为我想将我的
PrivateRoute
组件连接到redux存储。
Here is my code. 这是我的代码。
stateless component 无国籍组成部分
import React from 'react';
import {Route, Redirect} from 'react-router-dom';
import {auth} from './Authentication';
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={props =>
auth.isAuthenticated ? (
<Component {...props} />
) : (
<Component {...props} action="login"/>
)
}
/>
);
export default PrivateRoute;
I converted this component to stateful React
component like this. 我将此组件转换为有状态的
React
组件,就像这样。
stateful React component 有状态的React组件
import React from 'react';
import {Route, Redirect} from 'react-router-dom';
import {auth} from './Authentication';
import {connect} from 'react-redux';
class PrivateRoute extends React.Component {
render({ component: Component, ...rest }) {
return (
<Route
{...rest}
render={props =>
this.props.customer.isAuthenticated ? (
<Component {...props} />
) : (
<Component {...props} action="login"/>
)
}
/>
);
}
}
export default connect(state => state)(PrivateRoute);
Here, I am reading the data from redux store to check whether the user is authenticated or not. 在这里,我正在读取redux store中的数据,以检查用户是否已经过身份验证。
But the way I am converting the stateless component to stateful isn't correct. 但是我将无状态组件转换为有状态的方式是不正确的。
Am I passing the arguments render({ component: Component, ...rest })
correctly? 我正确地传递了参数
render({ component: Component, ...rest })
吗?
Will connecting the PrivateRoute
with redux store create any problem with props
as state=>state
will map state
to props
as well as ...rest
will have props
object? 将
PrivateRoute
与redux商店连接会产生任何props
问题,因为state=>state
会将state
映射到props
以及...rest
会有props
对象吗?
Not sure what is happening inside the code. 不确定代码中发生了什么。
Update AppRouter.js 更新 AppRouter.js
import React from 'react';
import {BrowserRouter, Route, Switch} from 'react-router-dom';
import {TransitionGroup, CSSTransition} from 'react-transition-group';
import PrivateRoute from './PrivateRoute';
import HomePage from './../components/HomePage';
import AboutUs from './../components/AboutUs';
import ContactUs from './../components/ContactUs';
import PageNotFound from './../components/PageNotFound';
import RestaurantList from '../components/RestaurantList';
import RestaurantMenu from '../components/RestaurantMenu';
import UserDetails from '../components/UserDetails';
import OrderConfirmation from '../components/OrderConfirmation';
import CustomerAccount from '../components/CustomerAccount';
import Logout from '../components/sections/Logout';
export default () => {
return (
<BrowserRouter>
<Route render={({location}) => (
<TransitionGroup>
<CSSTransition key={location.key} timeout={300} classNames="fade">
<Switch location={location}>
<Route path="/" component={HomePage} exact={true}/>
<Route path="/about" component={AboutUs} />
<Route path="/contact" component={ContactUs} />
<Route path="/restaurants" component={RestaurantList} />
<Route path="/select-menu" component={RestaurantMenu} />
<PrivateRoute path="/user-details" component={UserDetails} />
<PrivateRoute path="/order-confirmation" component={OrderConfirmation} />
<PrivateRoute path="/my-account" component={CustomerAccount} />
<PrivateRoute path="/logout" component={Logout} />
<Route component={PageNotFound} />
</Switch>
</CSSTransition>
</TransitionGroup>
)} />
</BrowserRouter>
);
}
In general, converting a stateless functional component (SFC) to a Component
is done like this: 通常,将无状态功能组件(SFC)转换为
Component
方式如下:
Create the class
shell for it. 为它创建
class
shell。
Copy the SFC's body to the render
method. 将SFC的主体复制到
render
方法。 If the SFC was an arrow function, add a return
as necessary to render
. 如果SFC是箭头函数,则根据需要添加
return
以进行render
。
Change any references to props
in the render
method to this.props
(or just add const { props } = this;
at the top). 将
render
方法中对props
任何引用更改为this.props
(或者只添加const { props } = this;
在顶部)。 SFCs receive their props in their arguments, but a component receives them as arguments to its constructor; SFC在其参数中接收它们的道具,但是一个组件将它们作为其构造函数的参数接收; the default constructor will save them as
this.props
. 默认构造函数将它们保存为
this.props
。
In your case, it's using destructuring on its arguments, so you could do the same with this.props
on the right-hand side of the destructuring: 在你的情况下,它在其参数上使用解构,所以你可以在
this.props
的右边使用this.props
做同样的this.props
:
const { component: Component, ...rest } = this.props;
That's it. 而已。 In your code, you've added parameters to the
render
function, but it doesn't get called with any arguments, and you've only changed props
to this.props
a bit haphazardly (including changing auth.isAuthenticated
to this.props.customer.isAuthenticated
for some reason). 在你的代码中,你已经为
render
函数添加了参数,但它不会被任何参数调用,并且你只是偶然地将props
更改为this.props
(包括将auth.isAuthenticated
更改为this.props.customer.isAuthenticated
由于某种原因)。
So applying 1-3 above: 所以应用1-3以上:
// #1 - the shell
class PrivateRoute extends React.Component {
// #2 - `render`, with the body of the SFC inside
render() {
// #3 - destructure `this.props`
const { component: Component, ...rest } = this.props;
// #2 (part 2) - add `return`
return <Route
{...rest}
render={props =>
auth.isAuthenticated ? (
<Component {...props} />
) : (
<Component {...props} action="login"/>
)
}
/>;
}
}
Your stateful component should be: 您的有状态组件应该是:
class PrivateRoute extends React.Component {
render() {
const { component: Component, ...rest } = this.props;
return (
<Route
{...rest}
render={props =>
this.props.customer.isAuthenticated ? (
<Component {...props} />
) : (
<Component {...props} action="login"/>
)
}
/>
);
}
}
Please see that there is some issue in render
parameter of Route
. 请注意
Route
render
参数中存在一些问题。 Here you have props
as function param but still using this.props.customer
, don't know the use case hence please fix it as per your application. 这里你有
props
作为函数参数,但仍然使用this.props.customer
,不知道用例因此请根据您的应用程序修复它。
Apart from it Component
and all the other data is already there in props of the component. 除了它之外,
Component
和所有其他数据已经存在于组件的道具中。 It won't be available in parameter of render
method in component. 它在组件中的
render
方法的参数中不可用。 Same destructuring as available in stateless component can be written in render
method as shown in code above. 无状态组件中可用的相同解构可以用
render
方法编写,如上面的代码所示。
Will connecting the PrivateRoute with redux store create any problem with props? 将PrivateRoute与redux商店连接会产生道具问题吗?
Yes, it would. 是的,它会的。 The way you have connected to the store will make store data available in
props
of component but external props
passed to component will not be available. 您连接到商店的方式将使商店数据在组件的
props
中可用,但传递给组件的外部props
将不可用。
For that you have to handle it in mapStateToProps
function: 为此你必须在
mapStateToProps
函数中处理它:
const mapStateToProps = (state, ownProps) => ({
...state,
...ownProps
});
Here mapStateToProps
has second parameter which has the external own props passed to component. 这里
mapStateToProps
有第二个参数,它有外部自己的道具传递给组件。 So you have to return it as well to make it available in component props
. 所以你必须返回它以使其在组件
props
可用。
Now connect would be like: 现在连接就像:
export default connect(mapStateToProps)(PrivateRoute);
I was having two queries. 我有两个疑问。
1) How to convert to Stateful Functional Component? 1)如何转换为有状态功能组件? 2) After connecting to the redux store will the props create a problem?
2)连接到redux商店后道具会产生问题吗?
My first query was solved by the answer provided by TJCrowder
. 我的第一个查询是由
TJCrowder
提供的答案解决的。
For a second query, I tried connecting the redux store
to the PrivateRoute
and I did get the data I was looking for. 对于第二个查询,我尝试将
redux store
连接到PrivateRoute
,我确实获得了我正在寻找的数据。
Here is the code which worked for me. 这是适合我的代码。
import React from 'react';
import {Route, Redirect} from 'react-router-dom';
import {connect} from 'react-redux';
class PrivateRoute extends React.Component {
render() {
const { component: Component, ...rest } = this.props;
const {customer} = this.props;
return <Route
{...rest}
render={props =>
customer.isAuthenticated ? (
<Component {...props} />
) : (
<Component {...props} action="login"/>
)
}
/>;
}
}
export default connect(state => state)(PrivateRoute);
Using this code I got the data that is coming from the routes, as well as the redux state inside the props. 使用此代码,我获得了来自路由的数据,以及props内的redux状态。
This is getting data coming from the routes const { component: Component, ...rest } = this.props;
这是从路由
const { component: Component, ...rest } = this.props;
获取数据const { component: Component, ...rest } = this.props;
This is the data coming from the redux store. 这是来自redux商店的数据。
const {customer} = this.props;
@TJCrowder has already written how to convert stateless component to stateful component in those 3 steps. @TJCrowder已经编写了如何在这3个步骤中将无状态组件转换为有状态组件。 so i will just write about connecting component to redux store like you did.
所以我会像你一样写关于将组件连接到redux商店。
I think connected components should always define mapStateToProps
and explicitly declare which data they depend on from the state. 我认为连接组件应始终定义
mapStateToProps
并显式声明它们从状态依赖的数据。
because the connected component rerenders if the connected property changes. 因为连接的组件会在连接的属性发生更改时重新呈现。 so it would be a bad idea to connect the whole application state to a component.
所以将整个应用程序状态连接到组件是个坏主意。 as it would mean that wheneever anything changes in application state rerender all connected components.
因为这意味着当应用程序状态发生任何变化时,重新渲染所有连接的组件。
better we define explicitly like the following that we depend on a property called data
(or anything you have) from the state. 我们更好地明确定义,如下所示,我们依赖于一个名为
data
(或你拥有的任何东西)的属性。 so in this case this component will only rerender if state.data
changes it wont rerender if state.xyz
changes. 所以在这种情况下,该组件将仅在重新呈现
state.data
改变,如果它不会重新呈现state.xyz
变化。
and this way you can take state.data and name it as you wish so it would not conflict with any existing props of the component. 这样你可以使用state.data并根据需要命名它,这样就不会与组件的任何现有道具发生冲突。
const mapStateToProps = (state, ownProps) => ({
data: state.data
});
export default connect(mapStateToProps)(PrivateRoute);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.