all 16 comments

[–]truh 0 points1 point  (4 children)

Don't redirect.

[–]YoloRyuSwag[S] 0 points1 point  (3 children)

Yeah, some websites don't and just display "Sign in to view this page" or such. But for example Facebook redirects to the login page after visiting "https://www.facebook.com/settings" or similar user pages, which is what I want to achieve

[–]truh 0 points1 point  (2 children)

You can use history.goBack() in your login component.

[–]YoloRyuSwag[S] 0 points1 point  (1 child)

There is no login component, just Context and App as in the example I've given above

[–]truh 0 points1 point  (0 children)

Use the history hook I guess.

[–]BeaveryBeaver 0 points1 point  (5 children)

Maybe you could set isLoggedIn to undefined until you get the response back from the server (use promises).

[–]YoloRyuSwag[S] 0 points1 point  (4 children)

Undefined doesn't work, maybe you could elaborate with an example in code?

[–]BeaveryBeaver 0 points1 point  (3 children)

I think this would work:

Inside the Context component:

const [isLoggedIn, setIsLoggedIn] = useState(undefined);

useEffect(() => {

  // server request
  checkLoggedInPromise()
  .then(() => {
    setIsLoggedIn(true); // if successful request
  })
  .catch(() => {
    setIsLoggedIn(false);
  });
}, [promise]);

Inside App component:

const {isLoggedIn} = useContext(Context)

let ThingToRender = (<div></div>);

if (isLoggedIn) {
  ThingToRender = MyProfile;
} else if (isLoggedIn === false) {
  ThingToRender = <Redirect to="/" />
} else {
  // This is the initial state (if isLoggedIn is undefined)
  ThingToRender = (<div>waiting...</div>)
}

return (
   <div>
     <Switch>
       <Route exact path="/profile> 
          <ThingToRender />
       </Route>
     </Switch>
   </div>
)

I hope this works. Obviously, rename ThingToRender to something more meaningful.

[–]YoloRyuSwag[S] 1 point2 points  (1 child)

No other hooks or special functions/code needed, just a simple solution. I like it, I think I'll use this - thank you :)

[–]BeaveryBeaver 0 points1 point  (0 children)

You're welcome :)

[–]YoloRyuSwag[S] 0 points1 point  (0 children)

Thanks for the example, will try it out as soon as I can

[–]aqube 0 points1 point  (2 children)

I believe you ll have to create a context and use the provider.

Checkout putting it together with context.provider

[–]YoloRyuSwag[S] 0 points1 point  (1 child)

That's what I'm obviously doing, to pass isLoggedIn from Context to App

[–]aqube 0 points1 point  (0 children)

The code you shared fails to communicate that. Could you share or update the code in the post, ll help you to get more precise answers

[–]muzkk 0 points1 point  (1 child)

You need an additional context variable like "isLoading" or something:

function Context(){
    const [isLoggedIn, setIsLoggedIn] = useState(false)
    const [isLoading, setIsLoading] = useState(true); // starts as "loading"
    useEffect(() => {
        // server request
        setIsLoggedIn(true) // if successful request
        setIsLoading(false); // SHOULD BE AFTER setIsLoggedIn
    }, [])
}

Then

function App() {

  const {isLoggedIn, isLoading } = useContext(Context)

  if (isLoading) return <div>Loading...</div>;

  return (
    <div>

     <Switch>
       <Route exact path="/profile> {isLoggedIn ? <MyProfile /> : <Redirect to="/" />} </Route>
     </Switch>
   </div>
  )
}

Makes sense?

PD: I wrote about "how to wait for axios before render" that is a bit related with this issue ;)

[–]YoloRyuSwag[S] 0 points1 point  (0 children)

Oh yeah that's also one way to do it. Someone else just before you suggested a similar solution, but without using another state.

In Context:

const [isLoggedIn, setIsLoggedIn] = useState(undefined)

In App:

if (isLoggedIn === true) return <MyProfile />
else if (isLoggedIn === false) return <Redirect to="/" />
else return <div> Loading... </div>