如何正确使用组合来组合封装在React-Redux中的受保护路线的HOC



我显然没有通过Redux掌握compose的概念,因为我无法按预期工作。

我目前在我的一个受保护的路线周围有两个嵌套HOC:一个确保在导航到受保护的路线之前对用户进行验证,而另一个只是一个计时器,如果他们闲置,则将它们从受保护的路线中踢出。<<<<<<<<。/p>

我想利用compose,以便可以清理我的代码,而不是在HOC中嵌套我的受保护路线。

这就是我目前拥有的:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import { routerMiddleware, ConnectedRouter } from 'react-router-redux';
import createHistory from 'history/createBrowserHistory';
// Render on every route
import App from './components/app';
// Route specific
import Signin from './containers/authentication/signin';
import Signout from './containers/authentication/signout';
import Home from './components/home';
// HoC to wrap protected routes in
import RequireAuth from './helpers/require_auth';
import Timer from './helpers/timer';
// Reducers 
import rootReducer from './reducers';
// SCSS for the project
import styles from '../assets/scss/main.scss';
const history = createHistory();
const initialState = {};
const enhancers = [];
const middleware = [thunk, routerMiddleware(history)];
if (process.env.NODE_ENV === 'development') {
    const devToolsExtension = window.devToolsExtension
    if (typeof devToolsExtension === 'function') {
        enhancers.push(devToolsExtension())
    }
}
const composedEnhancers = compose(applyMiddleware(...middleware), ...enhancers);
const store = createStore(rootReducer, initialState, composedEnhancers);
ReactDOM.render(
    <Provider store={store}>
        <ConnectedRouter history={history}>
            <div>
                <App />
                <Switch>
                    <Route exact path='/home' component={LeftSite(RequireAuth(Home))} />
                    <Route exact path='/auth/signout' component={Signout} />
                    <Route exact path='/auth/signin' component={Signin} />
                    <Route exact path='/' component={Signin} />
                </Switch>
            </div>
        </ConnectedRouter>
    </Provider>
    , document.querySelector('.container'));

我尝试过的是这样修改:

const composedEnhancers = compose(
                            applyMiddleware(...middleware),
                            ...enhancers
                        );
const protectedRoutes = compose(
                            applyMiddleware(RequireAuth, LeftSite)                            
                        );
const store = createStore(rootReducer, initialState, composedEnhancers, protectedRoutes);
ReactDOM.render(
    <Provider store={store}>
        <ConnectedRouter history={history}>
            <div>
                <App />
                <Switch>
                    <Route exact path='/home' component={protectedRoutes(Home)} />
                    <Route exact path='/auth/signout' component={Signout} />
                    <Route exact path='/auth/signin' component={Signin} />
                    <Route exact path='/' component={Signin} />
                </Switch>
            </div>
        </ConnectedRouter>
    </Provider>
    , document.querySelector('.container'));

这仅导致Cannot call a class as a function。这是HOC之一,因为它们都具有相似的结构:

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { authRequired } from '../actions/authentication';
export default function(ComposedComponent) {
    class AuthenticationRequired extends Component {
        // Check if the user has a token when protected route component is about to mount
        // Route them to / if they do not
        componentWillMount() {
            if (!sessionStorage.getItem('token')) {
                this.props.authRequired();
            }
        }
        // If the component will be updated then also check if user is authorized
        componentWillUpdate() {
            if (!sessionStorage.getItem('token')) {
                this.props.authRequired();
            }
        }
        // Render the component if passing these checks
        render() {
            return <ComposedComponent {...this.props} />
        }
    }
    // Conenct to the authRequired action
    return connect( null, { authRequired })(AuthenticationRequired);
}

我尝试了几种错误的错误。我不会把它们全部发布。我在这里看来它可能更接近正确的答案...也许?

我确实阅读了文档,这些文档对我的情况没有帮助:

https://paulkogel.gitbooks.io/redux-docs/content/docs/api/compose.html

所以我的问题是:

我应该如何构建compose

我应该如何仅在受保护的路线上称呼它?

就像文档所说的那样, compose实际上在概念上做了非常简单的事情:

所有撰写都是让您编写深度嵌套的函数转换,而无需代码的向右漂移。不要给它太多信用!

因此,假设您有三个非常简单的功能:

const capitalize = str => str.toUpperCase();
const takeFirstChar = str => str[0];
const prependHello = str => 'hello' + str;

如果您想连续使用所有三个,而不使用compose,则会成为这样的嵌套调用:

const originalValue = 'test';
console.log(  capitalize(takeFirstChar(prependHello(originalValue))))
// prints  'H' 
// (the first letter from the appended 'hello', capitalized)

请参阅如何调用第一个函数(prependHello)一直到右边?这就是"代码的向右漂移"的含义。

但是使用compose,我们可以这样写:

// NOTE the order of the arguments!
// The bottom one is applied first, then middle one, then the top one
const prependHelloAndTakeFirstCharToUpper = compose(
  capitalize,
  takeFirstChar,
  prependHello
);
console.log( prependHelloAndTakeFirstCharToUpper(originalValue)   )
// still prints 'H'

目前尚不清楚您在工作时如何使用HOC,但是如果您在此之前不涉及applyMiddleWare之类的东西,那么现在也可能不应该在那里。

我的猜测在不更多地了解您的代码的情况下应该做这样的事情:

const protectedRoutes = compose(RequireAuth, LeftSite);
// further down
<Route exact path='/home' component={protectedRoutes(Home)} />

,我认为您可以将protectedRoutes从参数中删除到createStore

最新更新