reactjs - React Router *Not Found* rendered first before main routes -
i working on huge project , have authorization system logged in users can access routes while not found component, served on logged out users. problem is, when user marked logged in , has valid token , proceed page (e.g /account), component not found rendered first , second later component account rendered correctly.
i have async componentdidmount validate token , if it's valid, set state of islogged: true. on each route in switch checking the state of islogged , send corresponding component.
my async componentdidmount
{/* username 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}); }; }); } }
this router (* supposing trying access /user page. notice use react-router, react-router-dom ^4.1.1* )
if (this.state.checking) { return null; } else { return ( <router> <switch> {/* not rendered first , not found rendered before falsly */} {this.state.islogged && <route exact path="/user" component={() => (<user islogged={this.state.islogged} username={username} />)} />} {/* rendered first , not found not rendering @ correctly */} <route exact path="/test" component={() => (<test islogged={this.state.islogged} />)} /> <route component={() => (<notfound islogged={this.state.islogged} />)} /> </switch> </router> );
i think problem in {this.state.islogged && ...} because if try access /test component rendered correctly without not found rendering first.
also, tested lifecycle methods
i think you're right , issue comes {this.state.islogged && ...}
lets take step step.
first this.state.islogged
falsy. mean <user islogged={this.state.islogged} username={username} />
not in reactrouter configuration.
we can guess reactrouter match default component (<route component={() => (<notfound islogged={this.state.islogged} />)} />
) since /user
not in configuration.
the actual behavior correct.
the fastest way archieve goal move token check child component :
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}); }; }); } }
rendering function :
render () { if(!this.state.islogged) return <span /> return <div>...</div> }
the main problem aproach require authenticated components implement this.
you'll need factorize code service avoid multiple calls.
a 2nd approach fatorize proxy component check :
<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>
this component 1 carry token check.
rendering function :
render () { if(!this.state.islogged) return <span /> return {this.props.children} }
main problem here can't share between component "this.state.islogged"
if want share , update mutiple component using global state, highly suggest give @ redux.
since redux can have hard learning curve, if need share single value, try things using observable pattern. (example : observable service, observable service + connector )
all code example not tested , here guide in right direction. in opinion there lot of way archieve want, sadly can tell why not work , hope gave enough clues find solution adapted use case.
Comments
Post a Comment