Search code examples
javascriptreactjsreact-hookscomponentsrendering

Re-render a component after using navigate('/path')


In this case, when the user logs in, he will be redirected to the messages page. I want the header component to be rendered after this, but it doesn't happen. If the header is rendered, a link will change, but if not rendered, the link will remain unchanged until the page is refreshed... what can I do?!

login.js:

const login = async (e) => {
    e.preventDefault();
    const result = await (
      await fetch("/portfolio/login", {
        method: "POST",
        credentials: "include",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(data),
      })
    ).json();
    if (result.accessToken) {
      navigate("/message");    //imported from @reach/router
    } else console.log(result.error);
    if (result.message) setRes(result.message);
  };

header.js:

const Header = () => {
  const [tokenObj, setToken] = useState('');
  
  useEffect(() => {
    fetch('/portfolio/verify', {method : "GET"})
    .then((res)=>{
      if(res.ok) return res.json(res);
    })
    .then((jsonRes)=> {
      if(jsonRes.token) setToken(jsonRes.token)
    });
  }, [tokenObj]);

  let lastNavLink;
  let lastNavHref;
  if(tokenObj){ 
    lastNavLink = 'Messages';
    lastNavHref = '/message'
  } else {
    lastNavLink = 'Login';
    lastNavHref = '/login';
  }
    return <a href={lastNavHref}> {lastNavLink} </a> //dynamic link
};

Solution

  • There are two things you need to keep in mind before jumping into the solution:

    1. Component re-renders based on State or Prop change, that's it.
    2. You got to save your login information in browser with something like localStorage so you know if user is logged in or not regardless of reloading your page.

    So coming back, you have to conditionally render the link based on the login info (it can be anything, but most probably user info and/or access/auth token) which you will be saving in the browser storage locally after logging in. But there's a problem, saving and getting back login data from localStorage wouldn't suffice because we need that data in form of state or prop since only then the component will react to the change. So to counter that you will have to somehow sync the data in localStorage with state/prop.

    To achieve this one could use a combination of redux, react-redux and redux-persist to counter this problem. So basically it would work the same way a normal redux flow works, but the main change will be done by persisting your login info through redux-persist. Once you will wrap your login reducer with redux-persist, it will automatically persist/sync your login reducer with localStorge. You might find a plenty of examples for this. So you would dispatch your login action after response is received with relevant data as its argument (which will be saved in store) and the rest will be handled by redux. After that you would just have to get your login state from redux in your header and based on that conditionally render your link.

    This is a one possible solution, but anyway you get the idea how it will work. You could use Context instead of Redux if you want but anyway you get the idea.