1

I want to redirect users to Unprotected (login/ register) components if the user is not logged in (or verified) else allow access to Protected components.

To achieve that, I tried to use,


ProtectedRoute techniques

  • PrivateRoute - failed to implement appropriately
  • RequiresLogin - This helped me to reach to the next approach
  • And some YouTube videos and articles found from Google

Code:

index.js

...
<Router>
    <App />
</Router>
...

App.js - using the ProtectedRoute

...
<Routes>
    <ProtectedRoute exact path={"page1"} element={<Page1 />}/>
    <ProtectedRoute exact path={"page2"} element={<Page2 />}/>
    <Route exact path={"login"} element={<Login />}/>
<Routes/>
...

RequireAuth

It seemed that it is a better approach then ProtectedRoute,

  • RequireAuth - works except, it is ProtectiveOverflow at the moment

Code:

index.js

// Unchanged

App.js

...
<Routes>
    <Route exact path={"page1"} element={
        <RequireAuth>
            <Page1 />
        </RequireAuth>
     }/>
    <Route exact path={"page2"} element={
        <RequireAuth>
            <Page2 />
        </RequireAuth>
     }/>
    <Route exact path={"login"} element={<Login />}/>
</Routes>
...

It seemed to work and I was able to protect the protected components. After implementing the authorization process, which I am doing by sending a fetch(...) request to my API (djangorestframework) and getting the result dynamically everytime, I figured out that the protected components got a bit more protective than required. Now, although the server authenticating the request and sending sucessfull response, the protected pages are still locked.

Digging up, I realized that I have used the fetch function which is a Promise and it runs on a separate thread. So, before the fetch could return the result, my component already gets rendered and unmounted.

Code:

RequireAuth.js

...
function RequireAuth({children}) {
    const [auth, setAuth] = useState(false);
    
    fetch(urls.auth, methods.get())
        .then(r => r.json())
        .then(data => {
            setAuth(data)
        })
        .catch(error => {
            console.log(error)
        });
    
    return auth? children : <Navigate to={"../login"}/>;
}
...

I have gone through various technique to solve this, for example,

Code:

RequireAuth.js

...
class RequireAuth extends React.Component {
    constructor(props) {
        super(props);
        this.state = {auth: false}

        fetch(urls.auth, methods.get())
        .then(r => r.json())
        .then(data => {
            this.setState({auth: data})
        })
        .catch(error => {
            console.log(error)
        });
    }

    render() {
        return this.state.auth? this.props.children : <Navigate to={"../login"}/>;
    }
}
...

However, that failed too. Then I looked into,


Finally,

I looked if I can do it using fetching or HttpRequest methods that does not run on different thread, but I afraid, even if it's possible, it can result in bad user experience. Therefore, please help me to solve this fetch authentication issue in React. And, I would also like if there were other ways to implement the dynamic authorization using React and djangorestframework that could do this protective page stuffs more efficiently.

Thank you.

1 Answer 1

0

Found this answer on StackOverflow as I could not stop searching just because I asked a question. This is very exciting and sad at the same time. I missed one very small part, I thought maybe it was not a very big deal. But guess what?


null is important


Yes, null is what I was missing while returning in my code. So, what I figured is if null is returned, react won't consider it as rendered and the render request will be keep asking, that's what I beleive. So I can simple set the default state of auth to be null and return null if it is null, else check the value of auth.

Code:

index.js

// Unchanged
...
<Router>
    <App />
</Router>
...

App.js

// Unchanged
...
<Routes>
    <Route exact path={"page1"} element={
        <RequireAuth>
            <Page1 />
        </RequireAuth>
     }/>
    <Route exact path={"page2"} element={
        <RequireAuth>
            <Page2 />
        </RequireAuth>
     }/>
    <Route exact path={"login"} element={<Login />}/>
</Routes>
...

RequireAuth.js - this is interesting

...
// Assumption: The server is sending `true` or `false` as the response for authentication for simplicity
function RequireAuth({children}) {
    const [auth, setAuth] = useState(null);  // The spell for the magic

    fetch(urls.auth, methods.get())
        .then(r => r.json())
        .then(data => setAuth(data))
        .catch(error => console.log(error));

    return auth == null?  // The code that did the magic
        null : (auth?
            children : <Navigate to={"/login"}/>)  // Notice, used '/login' instead of 'login' to directly go to login/ authenticate page which is at the root path.
...
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.