2017-08-18 115 views
0

我是一個龐大的系統工程工作的主要路線之前,我有一個授權系統,其中已登錄用戶可以訪問某些航線而未找到組件,在服務已註銷用戶。問題是,當用戶被標記爲登錄,並具有有效的標記,然後進行到頁面(例如/帳戶),組分未找到呈現第一和第二以後的部件帳戶呈現正確。陣營路由器*找不到*第一渲染

我有一個異步componentDidMount哪裏驗證我的令牌,如果它是有效的,我設置isLogged的狀態:真正。同樣在我的交換機中的每條路由上,我正在檢查isLogged的狀態,然後才發送相應的組件。

我的異步componentDidMount

{/* Username is from localstorage */} 

async componentDidMount() { 
    if ((USERNAME != "") && (USERNAME != null)) { 
    const logged = await checkTheToken({'Username': USERNAME}).then((result) => { 
     if(result.status == 202) { 
     this.setState({isLogged: true}); 
     this.setState({checking: false}); 
     }; 
    }); 
    } 
} 

這是路由器(*假設我們正在試圖訪問/用戶頁面。請注意,我用的反應路由器,反應路由器-DOM^4.1 0.1 *)

if (this.state.checking) { 
     return null; 
    } else { 
    return ( 
    <Router> 
     <Switch> 
      {/* This is Not Rendered First and Not Found rendered before FALSLY */} 

      {this.state.isLogged && <Route exact path="/user" component={() => (<User isLogged={this.state.isLogged} username={USERNAME} />)} />} 

      {/* This is Rendered First and Not Found is not rendering at all CORRECTLY */} 

      <Route exact path="/test" component={() => (<Test isLogged={this.state.isLogged} />)} /> 

      <Route component={() => (<NotFound isLogged={this.state.isLogged} />)} /> 
     </Switch> 
    </Router> 
    ); 

我認爲這個問題是在{this.state.isLogged & & ...},因爲如果我們嘗試訪問/test組件正確呈現沒有未找到先渲染。

另外,我測試了所有的生命週期方法

+0

您是否嘗試過在'componentWillMount'中進行身份驗證檢查,您的組件在它進入'componentDidMount'之前已經進行了渲染。 – Purgatory

+0

我測試了所有的生命週期方法 –

+0

您可能需要添加一個狀態字段,比如'checking「,默認爲'true'。當你得到一個響應時,成功或錯誤會將'checking'設置爲'false'。在你的render中if(this.state.checking)返回null;'。 – Purgatory

回答

1

我認爲你是對的,但問題是來自{this.state.isLogged && ...}

讓我們一步一步來。

第一個this.state.isLogged是虛假的。這意味着<User isLogged={this.state.isLogged} username={USERNAME} />目前不在ReactRouter配置中。

由於/user不在其配置中,我們可以猜測ReactRouter將匹配默認組件(<Route component={() => (<NotFound isLogged={this.state.isLogged} />)} />)。

實際行爲是正確的。

到archieve你的目標是將令牌檢查進入你的子組件像這樣的東西,最快的方式:

async componentDidMount() { 
    if ((USERNAME != "") && (USERNAME != null)) { 
    const logged = await checkTheToken({'Username': USERNAME}).then((result) => { 
     if(result.status !== 202) { 
     history.push('/not-found') 
     } else { 
     this.setState({isLogged: true}); 
     this.setState({checking: false}); 
     }; 
    }); 
    } 
} 

渲染功能將是這樣的:

render() { 
if(!this.state.isLogged) return <span /> 
return <div>...</div> 
} 

的主要問題有了這個問題,它會要求所有你的認證組件來實現這一點。

您還需要將代碼因子分解成服務以避免多次調用。

一個第二個辦法是fatorize成做檢查像這樣的代理組件這樣的:

<Router> 
    <Switch> 
     <Route component={Authenticated}> 
      <Route exact path="/user" component={() => (<User isLogged={this.state.isLogged} username={USERNAME} />)} /> 
     </Route> 
     <Route exact path="/test" component={() => (<Test isLogged={this.state.isLogged} />)} /> 
     <Route component={() => (<NotFound isLogged={this.state.isLogged} />)} /> 
    </Switch> 
</Router> 

該組件現在會是誰攜帶令牌檢查之一。

渲染功能是這樣的:

render() { 
if(!this.state.isLogged) return <span /> 
return {this.props.children} 
} 

主要這裏的問題是,你不能輕易您的組件之間共享「this.state.isLogged」

如果你想要分享使用一些全局狀態更新多個組件,我強烈建議你看看Redux

由於redux可能有一個很難的學習曲線,如果你只需要分享這個單一的值,你可以嘗試一些使用可觀察模式的東西。 (例如:observable service,observable service + connector

我所有的代碼示例都未經過測試,並且在這裏引導您朝着正確的方向發展。在我看來,有很多方法來實現你想要的東西,可悲的是我只能告訴你爲什麼它現在不起作用,我希望我給你足夠的線索來找到適合你的用例的解決方案。

+0

謝謝你的回答!我在每個相應的組件上移動了checkToken。因此,ComponentDidMount上的每個組件都必須檢查isLogged user。我不認爲這是優化(可能不是),但它的工作原理。我更喜歡避免多次調用db當我加載我的組件,我更喜歡通過道具傳遞值從一個組件到另一個,但我認爲是隻有這樣。 Regardin g第二種方法,我有反應路由器v4,我不能在我的路由器上添加嵌套路由。我試圖降級路由器,但我收到多個錯誤讓我知道,如果你想更新問題 –

+0

正如你所說我必須將代碼因子分解成服務。我會檢查它。 –

+1

我添加了一個服務共享值的示例https://jsfiddle.net/qcdmuzac/1/ – Okazari