0

I have the following Router:

// index.js  



 import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; 
    import history from "./history";
    const root = ReactDOM.createRoot(document.getElementById('root'));
    
    root.render(
    
        <Router history={history}>
            <Routes>
                <Route path='/Page1' element={<Page1/>} />
                <Route path='/Page2' element={<Page2/>} />
            </Routes>
        </Router>
    
    );

    // history.js
    
        import { createBrowserHistory } from 'history'
        
        export default createBrowserHistory();

I'm trying to pass data from Page1 to Page2 using <Link> from React-Router V6. To be more explicit, I'm doing this because Page1 contains a list of participants, each with an edit button. When the edit button is clicked, Page2 opens. Page2 is a form containing the data of the participant you want to edit. Here is a picture so you can visualize it.

enter image description here

Page1 is a class component while Page2 is a functional component with Hooks so that I can call useLocation(). After I retrieve the data from Page1, I want to pre-complete the form. Page2 is a functional component because in React-Router V6, you can only do this using useLocation() hook, as explained here

A) Page1 where I'm passing the data to Page2

//Page1


class CandidatesList extends Component {

 // ...

 listOfParticipants = this.state.listOfParticipants.map((participant) => {
 return(
 <Link to="/Page2" state={{participant: participant}} className="btn btn-primary">Edit Participant</Link> 
 // This is the edit button that opens Page2 while passing the data 

 )


}

B) Page2 where I'm retrieving the data from Page1

///////////// Page2

    // ...

    function Page2() {
    
    const { state } = useLocation()
    console.log(state.participant) // 

    useEffect(() => {
    /// ...

    }

}

However, it seems that the data is never received in Page2 and I get the following error (when I try to console.log() it)

Uncaught TypeError: Cannot read properties of null (reading 'participant')

What am I doing wrong and why is the data not getting passed?

AndrewHoover898
  • 159
  • 1
  • 9
  • 1
    Which `Router` is being imported and used? Can you share an example `participant` object value that is being passed in state? Is it a serializable object? – Drew Reese May 06 '22 at 17:27
  • import { BrowserRouter as Router, Routes, Route } from "react-router-dom"; It does not have anything to do with the object itself. I tried passing a primitive instead of a participant and the same issue occurs. – AndrewHoover898 May 06 '22 at 17:28
  • Is the `EditCandidates` component ***the*** `Page2` component in `index.js`? – Drew Reese May 06 '22 at 17:39
  • It is indeed. Sorry for the mistake, that was actually Page2, therefore function Page2() , I edited my original question. – AndrewHoover898 May 06 '22 at 17:39
  • 1
    FWIW I can't seem to reproduce the null state in this running [codesandbox](https://codesandbox.io/s/issues-while-trying-to-pass-data-from-one-page-to-another-using-link-from-react-05tjc7?file=/src/App.js), it's passed from Page1 to Page2. It's possible it's the way you are logging `console.log(state.participant)` as an unintentional side-effect, or not using a null check on the route state. You can see how I've correctly logged the state in a `useEffect` hook and check that `state` exists first before accessing into it. – Drew Reese May 06 '22 at 19:35

1 Answers1

0

I think I found the culprit, which should have been obvious and is a stupid mistake on my side...

My useEffect() function contains the following

   // Page2
   function Page2() {

       const {
           state
       } = useLocation()
       console.log(state.participant) 


       let someAsyncResult;
       useEffect(() => {
           if (!window.location.hash) {
               window.location = window.location + '#dataLoaded';
               window.location.reload();
           }
           async function fetchFromContract() {

               someAsyncResult = await remoteObject.fetchSomeRemoteStuff();
               // ... also setting state here using the someAsyncResult 

           }
           fetchFromContract();

       }, [])

   }

I'm doing the window.location stuff because otherwise I'd have to manually refresh the page anytime in order for someAsyncResult to get rendered. The page renders without it beforehand.

Anyway, so what is happening is that because the route becomes /Page2#dataLoaded after the async stuff is done, Page2 doesn't receive the props anymore since <Link>in Page1 referred to /Page2 not /Page2#dataLoaded

AndrewHoover898
  • 159
  • 1
  • 9