useMoralisQuery and useNavigate

I’m not sure this is more related to the hook “useMoralisQuery” or to the hook “useNavigate” from react-router-dom v6, but I can’t find a solution.

MainRouter.js

<BrowserRouter>
      <NavBar/>
      <Routes>     
          <Route exact path="/"  element={<HomePage/>}></Route>
          <Route path="item"  element={<ShowItem/>}>
            <Route path=":itemId"  element={<ShowItem/>}>
            </Route>
          </Route>
      </Routes>
  </BrowserRouter>

The navbar includes a search bar s.t. I’m able to search different items: “item/1”, “item/2”, … For sake of semplicity, I replace the search bar with a button which try to redirect always to item 12

NavBar.js

return (
    [...]
    <button onClick={()=>navigate("/item/12")}>Click</button>
);

The ShowItem component should fetch my Moralis class marketItem matching the itemId.

ShowItem

function ShowItem(){
    const match = useMatch('item/:itemId');
    const { data, error, isLoading } = useMoralisQuery("marketItem", query =>
        query.equalTo("tokenId", match.params.itemId))
    
    let NFT = JSON.parse(
        JSON.stringify(data, [
            "tokenId",
            "itemId",
            "minter",
            "price",
            "commissioni",
            "tokenURI",
            "hasPvtImg"
        ])
    )[0]


    return(
        <>
            {
                NFT ?
                <>{NFT.tokenId} found</>
                :
                <div>{match.params.itemId} not found</div>
            }
        </>
        );
}

If I’m in any page but “item/*”, the navigation works as expected. Ex. if I’m at “homepage”, the button redirects to “item/12” and the data is loaded

However, the strange behaviour happens if my current page is “item/*”, ex. “item/1”. In this case, if I press the button the url changes to “item/12” but the content doesn’t load: the correct content is loaded only if I manually refresh the page

Do you have any suggestion? Thanks

This sounds like a render issue (based on it working when you refresh the page, not when you navigate to it).

E.g. use the useState hook for your let NFT so the component re-renders when the variable value changes.

Do you mean something like this?

    const match = useMatch('item/:itemId');
    const { data, error, isLoading } = useMoralisQuery("marketItem", query =>
        query.equalTo("tokenId", match.params.itemId))
    const [NFT,setNFT] = useState()


    useEffect(() =>{
        let DATA = JSON.parse(
            JSON.stringify(data, [
                "tokenId",
                "itemId",
                "minter",
                "price",
                "commissioni",
                "tokenURI",
                "hasPvtImg"
            ])
        )[0]
        
        setNFT(DATA)
    },[match])

Doesn’t work. And the problem I think is in:

const { data, error, isLoading } = useMoralisQuery("marketItem", query =>
        query.equalTo("tokenId", match.params.itemId))

It looks like when the component is hit by the useNavigate, the query is not updated and still fetch the previous ItemId. Neither I can put the useMoralisQuery inside a hook useEffect

I’ve not be able to find a solution using useMoralisQuery.
I had to fall back to useMoralis instead

async function Query(Moralis,itemId){
    const marketItem = Moralis.Object.extend("marketItem");
    const query = new Moralis.Query(marketItem);
    query.equalTo("tokenId", itemId);
    const object = await query.find();
    let DATA = JSON.parse(
        JSON.stringify(object, [
            "tokenId",
            "itemId",
            "minter",
            "price",
            "commissioni",
            "tokenURI",
            "hasPvtImg"
        ])
    )[0]
    return DATA
};

function ShowItem(){
    const match = useMatch('item/:itemId');
    const {Moralis,isInitialized } = useMoralis();
    const [NFT,setNFT] = useState([])

    async function foo(){
        let ris = await Query(Moralis,match.params.itemId)
        setNFT(ris)
    }

    useEffect(() =>{
        if (isInitialized ){
            foo()
        }
    },[match,isInitialized])

    
    return(
        <>
            {
                NFT?
                <>{NFT.tokenId}</>
                :
                null
            }
        </>       
        );
}

Something like this works as expected

Looks good to me - possibly an issue with the match dependency in the useEffect, you shouldn’t need it.

I was about to suggest formatting the data before you return it in your query so you can simplify the data fetching to output process which you’ve done in the useMoralis example.

In that case, you should be able to just render the data straight from useMoralisQuery’s data, like you’ve done there in the second example - what do you get when you log data when you navigate to a new item? E.g. console.log(data) in a useEffect with [data].