2017-04-20 138 views
14

我已經稍微調整了專用路由的React路由器示例,以便與Redux一起玩,但在鏈接或重定向到其他「頁面」時不顯示任何組件。這個例子可以在這裏找到:React路由器私有路由/重定向不起作用

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

他們PrivateRoute組件看起來是這樣的:

const PrivateRoute = ({ component: Component, ...rest }) => (
    <Route {...rest} render={props => (
    fakeAuth.isAuthenticated ? (
     <Component {...props}/> 
    ) : (
     <Redirect to={{ 
     pathname: '/login', 
     state: { from: props.location } 
     }}/> 
    ) 
)}/> 
) 

但是,因爲我已經在一個終極版的應用程序結合的話,我不得不調整PrivateRoute一點這樣我就可以訪問了Redux店,以及路線道具:

const PrivateRouteComponent = (props) => (
    <Route {...props.routeProps} render={() => (
    props.logged_in ? (
     <div>{props.children}</div> 
     ) : (
     <Redirect to={{ 
      pathname: '/login', 
      state: { from: props.location } 
     }} />) 
    )} /> 
); 

const mapStateToProps = (state, ownProps) => { 
    return { 
     logged_in: state.auth.logged_in, 
     location: ownProps.path, 
     routeProps: { 
      exact: ownProps.exact, 
      path: ownProps.path 
     } 
    }; 
}; 

const PrivateRoute = connect(mapStateToProps, null)(PrivateRouteComponent); 
export default PrivateRoute 

每當我不登錄,並觸及PrivateRoute,我是心病直接重定向到/登錄。但是,例如,在登錄並使用<Redirect .../>或點擊任何<Link ...>到PrivateRoute後,URI會更新,但視圖不會。它保持在同一個組件上。

我在做什麼錯?


剛剛完成的圖片,在應用程序的index.js有一些無關痛癢的東西,這些路由設置是這樣的:

ReactDOM.render(
    <Provider store={store}> 
     <App> 
      <Router> 
       <div> 
        <PrivateRoute exact path="/"><Home /></PrivateRoute> 
        // ... other private routes 
        <Route path="/login" component={Login} /> 
       </div> 
      </Router> 
     </App> 
    </Provider>, 
    document.getElementById('root') 
); 

回答

4

只是有同樣的問題,我解決它通過使我應用終極版容器和傳球isAuthenticated爲道具,以PrivateRoute

這是,我希望它能幫助

const App = (props) => { 
return (
    <Provider store={store}> 
    <Router> 
     <div> 
     <PrivateRoute path="/secured" component={Secured} isAuthenticated={props.isAuthenticated} /> 
     </div> 
    </Router> 
    </Provider> 
); 
}; 

const mapStateToProps = state => ({ 
    isAuthenticated: state.isAuthenticated 
}); 

export default connect(mapStateToProps)(App); 

然後在我的PrivateRoute

const PrivateRoute = ({ component: Component, isAuthenticated, ...rest}) => (
<Route 
    {...rest} 
    render={props => (
    isAuthenticated 
    ? (
     <Component {...props} /> 
    ) 
    : (<Redirect to={{ pathname: '/login', state: { from: props.location} }} />) 
)} 
/> 
); 

export default PrivateRoute; 
+0

謝謝,我會在晚些時候看看! :-D – Rein

+0

我有類似的問題。事實上,我不想通過isAuthenticated到每一次使用PrivateRoute,這是我連接到Redux的原因,但令人驚訝的是,直到任何額外的道具傳遞給

+0

@Danijel,你搖滾! :-) – kernix

0

我有類似的問題像@Rein。就我而言,PrivateRoute看起來與原始版本幾乎相同,但只連接到Redux並在原始示例中使用它代替fakeAuth。

const PrivateRoute = ({ component: Component, auth, ...rest }) => (
    <Route 
    {...rest} 
    render={props => 
    auth.isAuthenticated 
    ? <Component {...props} /> 
    : <Redirect to={{ pathname: "/login" }} />} 
    /> 
); 

PrivateRoute.propTypes = { 
    auth: PropTypes.object.isRequired, 
    component: PropTypes.func.isRequired 
} 

const mapStateToProps = (state, ownProps) => { 
    return { 
    auth: state.auth 
    } 
}; 

export default connect(mapStateToProps)(PrivateRoute); 

使用和結果: -

  1. 不工作,但期待工作
    • <PrivateRoute path="/member" component={MemberPage} />
  2. 工作,但不希望用這樣的
    • <PrivateRoute path="/member" component={MemberPage} auth={auth} />
  3. 工作。只是工作,但不希望被使用。從這一點可以理解,如果你將原始的PrivateRoute連接到Redux,你需要傳遞一些額外的道具(任何道具)來使PrivateRoute工作,否則它不起作用。 任何人,請對此行爲給予一些提示。這是我主要關心的問題。As a New Question at
    • <PrivateRoute path="/member" component={MemberPage} anyprop={{a:1}} />
6

你需要用你的Route<Switch>標籤

ReactDOM.render(
<Provider store={store}> 
    <App> 
     <Router> 
      <div> 
       <Switch> 
        <PrivateRoute exact path="/"><Home /></PrivateRoute> 
        // ... other private routes 
        <Route path="/login" component={Login} /> 
       </Switch> 
      </div> 
     </Router> 
    </App> 
</Provider>, 
document.getElementById('root')); 
+0

爲什麼這個有效? –

+0

您必須讓組件重新呈現。它也可以將PrivateRoute設置爲非純粹的: 'export default connect(mapStateToProps,null,null,{pure:false})(PrivateRoute);' 請參閱本文[Stack Overflow](https:// stackoverflow。 com/questions/43892050/react-router-4-x-privateroute-not-working-after-connecting-to-redux) – worker11811

+0

我正在嘗試在與'withRouter'連接的組件內部使用'props.history.push' ,沒有'Switch',我的'PrivateRoute'不工作。爲我節省了一堆時間,謝謝! – jordancooperman

2

我設法得到這個工作使用rest參數從mapStateToProps訪問數據:

const PrivateRoute = ({component: Component, ...rest}) => { 
    const {isAuthenticated} = rest; 

    return (
    <Route {...rest} render={props => (
     isAuthenticated ? (
     <Component {...props}/> 
    ) : (
     <Redirect to={{ 
      pathname: '/login', 
      state: {from: props.location} 
     }}/> 
    ) 
    )} 
    /> 
); 
}; 

PrivateRoute.propTypes = { 
    isAuthenticated: PropTypes.bool.isRequired, 
}; 

function mapStateToProps(state) { 
    return { 
    isAuthenticated: state.user.isAuthenticated, 
    }; 
} 

export default connect(mapStateToProps)(PrivateRoute); 
+0

我不得不這樣做,以及添加''的路線,使其工作。 – worker11811

0

根據react-router documentation你可能只是換你connect功能與withRouter

// before 
export default connect(mapStateToProps)(Something) 

// after 
import { withRouter } from 'react-router-dom' 
export default withRouter(connect(mapStateToProps)(Something)) 

這個工作對我和我的觀點開始被用在這種情況下的行車路線更新。

1

嗯,我認爲這個問題的答案應該更加詳細,所以我在這裏,經過4個小時的挖掘。

當你用connect()包裝你的組件時,React Redux實現了shouldComponentUpdate(sCU,如果你在github問題上搜索答案)並且對道具進行淺層比較(它通過道具對象中的每個關鍵點並檢查值與'==='相同)。在實踐中意味着你的組件被認爲是Pure只有當它的道具改變時,它纔會改變!這裏是關鍵信息。 第二個關鍵信息,React路由器與上下文一起工作,將路由器的位置,匹配和歷史記錄對象傳遞給Route組件。 它不使用道具

現在,讓我們在實踐中發生什麼看,因爲即使知道,我覺得還是相當棘手:

  • 案例:

連接後有3關鍵是你的道具:路徑,組件和auth(由連接給出)。所以,事實上,你的封裝組件不會在路由更改時重新渲染,因爲它不關心。當路線改變時,你的道具不會改變,它不會更新。

  • 案例:

現在有4個按鍵到你的道具後連接:路徑,組件,權威性和anyprop。這裏的技巧是anyprop是每次調用組件時創建的對象。因此,無論何時調用組件,都會進行比較:{a:1} === {a:1},哪個(您可以嘗試)會讓您錯誤,所以您的組件現在每更新一次。但請注意,您的組件仍然不關心路由,它的孩子會這樣做。

  • 案例:

現在,這奧祕在這裏,因爲我想你把這個線在你的應用程序文件,應該沒有提及「權威性」,在那裏,你應該有一個錯誤(至少這就是我所說的)。我的猜測是你的App文件中的「auth」引用了一個定義在那裏的對象。

現在我們該怎麼辦?

在這裏我看到兩個選項:

  1. 泰爾陣營終極版,你的分量不是純粹的,這將刪除SCU注入和您的組件現在將正確更新。

    連接(mapStateToProps,NULL,NULL,{ 純:假 })(PrivateRoute)

  2. 使用WithRouter(),這將導致當道具注入的位置,比賽和歷史物件到您的組件。現在,我不知道內部結構,但是我懷疑React路由器不會改變這些對象,所以每當路由改變時,它的道具改變(sCU返回true)以及你的組件正確更新。這樣做的副作用是,你的陣營樹現在有很多的WithRouter和路線的東西污染......

參考GitHub的問題:Dealing with Update Blocking

你可以在這裏看到,withRouter意作爲quickfix,但不是推薦的解決方案。使用pure:false並沒有提到,所以我不知道這個修復程序有多好。

我發現了第三個解決方案,雖然我不清楚它是否比使用高級組件的路由器更好的解決方案。你把你的高階組件連接到Redux商店,現在你的路線不會對它渲染的東西有所詛咒,HOC會處理它。

import Notlogged from "./Notlogged";  
function Isloggedhoc({ wrap: Component, islogged, ...props }) { 
     return islogged ? <Component {...props} /> : <Notlogged {...props} />; 
    } 

const mapState = (state, ownprops) => ({ 
     islogged: state.logged, 
     ...ownprops 
    }); 

export default connect(mapState)(Isloggedhoc); 
在App.js

<Route path="/PrivateRoute" render={props => <Isloadedhoc wrap={Mycomponent} />} /> 

你甚至可以做咖喱函數縮短了一點:

function isLogged(component) { 
    return function(props) { 
    return <Isloadedhoc wrap={component} {...props} />; 
    }; 
} 

使用它,這樣的:

<Route path="/PrivateRoute" render={isLogged(Mycomponent)} /> 
+0

嗯,我認爲這會在[link](https://stackoverflow.com/a/43889596/8674856)之後出現,但它不會。我的答案旨在建立在他的問題的具體細節上,儘管它可以應用於原始問題。 – TheoH