Home > OS >  useLocation doesn't recognize JSON object in state
useLocation doesn't recognize JSON object in state

Time:05-19

I've been trying to pass a JSON object from one component to another using useNavigate() and useLocation() in react-router-dom. I've tried various ways of doing this, following this, and this. The problem is, I am calling navigate() within a async function that is triggered after a button is clicked, so I cannot use the Link component I'd imagine.

How it should work is that once the submit button is clicked, it triggers an API call. Ideally, nce the JSON object is received, navigate() is called, passing the JSON object to the next component. However, I keep getting "null" or an empty object.

Please check this link to see what I mean.

Screenshot of console log output of result when accessed from useLocation


App.JS Routes:

<BrowserRouter>
  <Routes>
    <Route path="/" element={<Home />} />
    <Route path="/start/:id" element={<Start/>} />
    <Route path="/quiz/:id" element={<Quiz/>} />
    <Route path="/results" element={<Results />} />
  </Routes>
</BrowserRouter>

Navigating to '/results' from 'quiz', passing results (JSON object) to :

import { useLocation } from "react-router-dom";

...

 const toResults=()=>{
      console.log(results); // *Properly displays JSON object in console)*
      navigate('/results', {state: results});
    }

Accessing JSON from '/results' (not working):

import { useLocation } from "react-router-dom";

...

const { state } = useLocation();
    
      useEffect(() => {
        console.log("Results from results page: ");
        console.log(state);
      }, [])

API Call where toResults() is called:

   async function submitQuiz(event){ 
   event.preventDefault();
   console.log(id);
   console.log(answer);

   //Post request passes question ID and student answer to server.
   const response = await fetch('http://localhost:3001/api/quiz', {
    
       method: 'POST',
       headers:{
          'Content-Type': 'application/json' ,
          'Accept': 'application/json' 
       },
       body: JSON.stringify({
           id,
           answer
       })  
   } ) .then(response => response.json())
   .then(data => {
     console.log(data);
     setResults(data);
     toResults();
    });
  }

I would appreciate any guidance on how to properly access data from useLocation, or if there is a more efficient way to accomplish this.

Thank you!

CodePudding user response:

Issue

The issue here is that results is your React state and enqueued React state updates are not immediately processed.

.then(data => {
  console.log(data);
  setResults(data); // <-- enqueued state update
  toResults();      // <-- uses current `results` state
});

...

const toResults=()=>{
  console.log(results); // <-- not updated state yet
  navigate('/results', {state: results});
}

Solution

You very likely don't need the result state at all. Since you are navigating away from this component the state will be garbage collected anyway. Just issue the imperative navigation request with the response data.

Example:

async function submitQuiz(event){ 
  event.preventDefault();
  console.log(id);
  console.log(answer);

  //Post request passes question ID and student answer to server.
  const response = await fetch(
    'http://localhost:3001/api/quiz',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json' ,
        'Accept': 'application/json' 
      },
      body: JSON.stringify({
        id,
        answer
      })  
    })
    .then(response => response.json())
    .then(data => {
      console.log(data);
      navigate('/results', { state: data }); // <-- navigate with result here
    });
}
  • Related