Home > Software engineering >  Navigate with page reload using react router
Navigate with page reload using react router

Time:01-24

My application uses a Laravel backend and a React frontend. Ordinarily, I would use e.preventDefault() so that there are no page reloads. The issue I am having is that if I login or logout without a page refresh, it causes a CSRF mismatch on future requests. So I'm okay with the page refresh. However, when I remove e.preventDefault(), the form data becomes appended to the URL. The best solution I have been able to come up with is this:

  let csrfToken = document.head.querySelector('meta[name="csrf-token"]').content;

  const navigate = useNavigate()

  const handleLogin = async (e) => {
    e.preventDefault()
      axios.post('login', {email, password}, {
        'X-CSRF-TOKEN': csrfToken
      })
      .then(() => {
        setLoginStatus(true)
        navigate('/')
        window.location.reload();
      })
  }

This essentially works, but I don't like it. What happens is that the view is updated with the Component at '/,' and then the page refreshes. It just looks weird. All I want is for the Component at '/' to be rendered upon the form's submission with a page reload. Keeping in mind my problem with removing e.preventDefault(), where the form data gets added to the URL.

CodePudding user response:

I couldn't realize this problem. But I think you can use useEffect and useState together.

For example: When the login operation finishes, set the data which will be gained to state. And make dependency with useEffect and that state. So if the state change the component automaticaly re-render beacuse of the useEffect. In this case no reload needed.

CodePudding user response:

I had accepted an answer to the question, but that answer has disappeared. For the sake of anyone else who might find this after being stuck on the same issue, the key that helped me to solve this issue was creating a back-end route to retrieve the CSRF cookie, creating a state value which updates and then triggers a useEffect() to make the front-end match the updated CSRF token that is generated upon logging in and logging out. This allows the login and logout functionality to work properly without requiring a page refresh. Here are the relevant bits of code:

  const [csrfToken, setCsrfToken] = useState('')

  useEffect(() => {
    axios.get('csrf-token')
    .then((e) => {
      setCsrfToken(e.data)
      axios.defaults.headers.common['X-CSRF-TOKEN'] = csrfToken;
    })
  }, [csrfToken])

  const handleLogin = async (e) => {
    e.preventDefault()
    axios.post('login', {email, password})
    .then((e) => {
      return axios.get('csrf-token')
    })
    .then((e) => {
      setCsrfToken(e.data)
      navigate('/', { replace: true });
    })
  }

  const handleLogout = async (e) => {
    e.preventDefault()
    axios.post('logout')
    .then(() => {
      return axios.get('csrf-token')
    })
    .then((e) => {
      setCsrfToken(e.data)
      navigate('/', { replace: true });
    })
  }

With the route defined in Laravel's web.php being simply:

Route::get('/csrf-token', function() {
    $csrfToken = csrf_token();
    return $csrfToken;
});
  • Related