首页 > 解决方案 > 将具有参数的无状态 React 组件转换为有状态

问题描述

在我的 React JS 项目中,我正在处理PrivateRoutes. 我已经完成了这个私有路由和使用react-router-dom.

https://reacttraining.com/react-router/web/example/auth-workflow

根据这个文档,他们创建了一个PrivateRoute作为无状态组件。

但我的要求是将它转换为有状态的 React 组件,因为我想将我的PrivateRoute组件连接到 redux 存储。

这是我的代码。

无状态组件

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;

我将此组件转换为React像这样的有状态组件。

有状态的 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);

在这里,我正在从 redux 存储中读取数据以检查用户是否经过身份验证。

但是我将无状态组件转换为有状态的方式是不正确的。

render({ component: Component, ...rest })是否正确传递了论点?

PrivateRoute与 redux 存储连接会产生任何问题,props因为state=>state将映射stateprops以及...rest将有props对象?

不确定代码内部发生了什么。

更新 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>
    );
}

标签: javascriptreactjsreact-routerreact-redux

解决方案


通常,将无状态功能组件 (SFC) 转换为 aComponent是这样完成的:

  1. 为它创建class外壳。

  2. 将 SFC 的主体复制到render方法中。如果 SFC 是箭头函数,则return根据需要添加 a 到render.

  3. propsrender方法中的任何引用更改为this.props(或仅const { props } = this;在顶部添加)。SFC 在其参数中接收它们的道具,但组件将它们作为其构造函数的参数接收;默认构造函数会将它们保存为this.props.

    在您的情况下,它在其参数上使用解构,因此您可以this.props在解构的右侧执行相同的操作:

     const { component: Component, ...rest } = this.props;
    

而已。在您的代码中,您已经向render函数添加了参数,但它没有被任何参数调用,并且您只是随意更改为(包括props出于某种原因更改为)。this.propsauth.isAuthenticatedthis.props.customer.isAuthenticated

所以应用上面的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"/>
        )
      }
    />;
  }
}

推荐阅读