Data fetching not happening when I use two parameters in React Router Dom and navigate directly on the page

huangapple go评论67阅读模式
英文:

Data fetching not happening when I use two parameters in React Router Dom and navigate directly on the page

问题

I will only translate the code portions you provided. Here's the translation:

我在React Router中遇到了一个非常奇怪和复杂的问题我试图实现一个单页面应用页面数量取决于JSON文件中的产品数量

在我的应用中我有一个主页面它始终只包含一个页面因此只有一个参数称为:section我遇到的问题仅在我使用第二个参数:page_number时发生所有其他页面都有这个参数

这是我的主要组件包含各种页面并依赖于路由参数

```jsx
import { Routes, Route } from 'react-router-dom';
import GoodsList from './GoodsList';
import Pages from './Pages';

function Sections() {
    return (
        <Routes>
            <Route path='' element={
                <>
                    <div className="pageContent" data-main="true">
                        <p>Novelties</p>
                        <GoodsList goods="novelties" />
                        <p>Hot</p>
                        <GoodsList goods="hot" />
                    </div>
                </>
            } />
            <Route path='/:section/:page_number' element={
                <>
                    <div className='pageContent'>
                        <GoodsList />
                        <Pages />
                    </div>
                </>
            } />
        </Routes>
    )
}

我使用这个组件来导航到页面:

import { Link } from 'react-router-dom';

function Menu() {
    return (
        <nav className='menu'>
            <ul>
                <li>
                    <Link to="">Main</Link>
                </li>
                <li>
                    <Link to="figures/1">Figures</Link>
                </li>
                <li>
                    <Link to="dakimakuras/1">Figures</Link>
                </li>
                <li>
                    <Link to="manga/1">Manga</Link>
                </li>
                <li>
                    <Link to="other/1">Other merch</Link>
                </li>
            </ul>
        </nav>
    )
}

最后,这个组件显示产品列表:

import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchProducts } from '../redux/fetchDataReducer';
import { useParams } from 'react-router-dom';

function GoodsList(props) {
    const params = useParams();
    const goods = returnGoods();
    function returnGoods() {
        if (document.location.pathname === "/") {
            return props.goods;
        }
        return params.section;
    }

    const dispatch = useDispatch();
    useEffect(() => {
        dispatch(fetchProducts());
    }, []);

    const products = useSelector(state => state.fetchDataReducer.products);

    return (
        <div className="list">
            {products && products[goods].map((good, i) => (
                <div className="productCard" key={i}>
                    <div className="productPicture">
                        <img src={good.pic} alt="ERROR" />
                    </div>
                    <p className="productName">{good.name}</p>
                </div>
            ))}
        </div>
    )
}

如果您需要更多帮助,请告诉我。

英文:

I faced a really strange and complex problem with React Router. I am trying to implement a single page application with a varying number of pages that depends on the number of products in the json file.
In my app I have the main page that always consist only of one pages thus it has only one paramater which is called :section. The bug I'm stuck with happens only when I use the second parameter :page_number, all other pages have this parameter.

This is my main component that contains various pages and depends on the router params

import { Routes, Route } from &#39;react-router-dom&#39;;
import GoodsList from &#39;./GoodsList&#39;;
import Pages from &#39;./Pages&#39;;

function Sections() {
    return (
        &lt;Routes&gt;
            &lt;Route path=&#39;&#39; element={&lt;&gt;
                &lt;div className=&quot;pageContent&quot; data-main=&quot;true&quot;&gt;
                    &lt;p&gt;Novelties&lt;/p&gt;
                    &lt;GoodsList goods=&quot;novelties&quot; /&gt;
                    &lt;p&gt;Hot&lt;/p&gt;
                    &lt;GoodsList goods=&quot;hot&quot; /&gt;
                &lt;/div&gt;
            &lt;/&gt;} /&gt;
            &lt;Route path=&#39;/:section/:page_number&#39; element={&lt;&gt;
                &lt;div className=&#39;pageContent&#39;&gt;
                    &lt;GoodsList /&gt;
                    &lt;Pages /&gt;
                &lt;/div&gt;
            &lt;/&gt;} /&gt;
        &lt;/Routes&gt;
    )

This component I use for navigation on the page

import { Link } from &#39;react-router-dom&#39;;

function Menu() {
    return (
        &lt;nav className=&#39;menu&#39;&gt;
            &lt;ul&gt;
                &lt;li&gt;
                    &lt;Link to=&quot;&quot;&gt;Main&lt;/Link&gt;
                &lt;/li&gt;
                &lt;li&gt;
                    &lt;Link to=&quot;figures/1&quot;&gt;Figures&lt;/Link&gt;
                &lt;/li&gt;
                &lt;li&gt;
                    &lt;Link to=&quot;dakimakuras/1&quot;&gt;Figures&lt;/Link&gt;
                &lt;/li&gt;
                &lt;li&gt;
                    &lt;Link to=&quot;manga/1&quot;&gt;Manga&lt;/Link&gt;
                &lt;/li&gt;
                &lt;li&gt;
                    &lt;Link to=&quot;other/1&quot;&gt;Other merch&lt;/Link&gt;
                &lt;/li&gt;
            &lt;/ul&gt;
        &lt;/nav&gt;
    )
}

And finaly this component displays the list of products

import { useEffect } from &#39;react&#39;;
import { useDispatch, useSelector } from &#39;react-redux&#39;;
import { fetchProducts } from &#39;../redux/fetchDataReducer&#39;;
import { useParams } from &#39;react-router-dom&#39;;

function GoodsList(props) {
    const params = useParams();
    const goods = returnGoods();
    function returnGoods() {
        if (document.location.pathname == &quot;/&quot;) {
            return props.goods
        }
        return params.section
    }
    
    const dispatch = useDispatch();
    useEffect(() =&gt; {
        dispatch(fetchProducts());
    }, [])
    
    const products = useSelector(state =&gt; state.fetchDataReducer.products);
    
    return (
        &lt;div className=&quot;list&quot;&gt;
            {products &amp;&amp; products[goods].map((good, i) =&gt; (
                &lt;div className=&quot;productCard&quot; key={i}&gt;
                    &lt;div className=&quot;productPicture&quot;&gt;
                        &lt;img src={good.pic} alt=&quot;ERROR&quot; /&gt;
                    &lt;/div&gt;
                    &lt;p className=&quot;productName&quot;&gt;{good.name}&lt;/p&gt;
                &lt;/div&gt;
            ))}
        &lt;/div&gt;
    )
}

The thing is when I click on the main page in the nav bar or move to it directly by typing the path in the address bar it always works fine. Then if I click on any section in the nav bar everything works fine either, BUT if I will try to refresh the page or move to any of the pages except the main by directly typing its address in the bar the GoodsList component won't load the products list. The fetching of data won't happen somehow, but the component itself and all the parameters from the address bar will be loaded fine. BUT if I will move to the main page again and then to any other section by using the nav Link it will be loaded fine again and the problem won't appear till I refresh the page.

So, the problem appears only if I have the :page_number parameter and affects only the data I recieve from json file through Redux. If I delete this second parameter the bug won't happen. It happens when I move to any section with this parameter directly or refresh the page, if I use navigation links on my menu bar it works fine but ONLY if I visited the main page before that.

UPD. Adding the pages component

import { useSelector } from &quot;react-redux&quot;;
import { Link, useParams } from &#39;react-router-dom&#39;;

function Pages() {
    const params = useParams();
    const products = useSelector(state =&gt; state.fetchDataReducer.products);
    const currentProduct = products ? products[params.section] : [];
    const pageLinks = [];

    let numberOfPages = () =&gt; {
        if ((currentProduct.length / 8) % 1 == 0) {
            return currentProduct.length / 8
        }
        else return Math.floor((currentProduct.length / 8) + 1)
    }

    for (let x = 1; x &lt; (numberOfPages() + 1); x++) {
        pageLinks.push(&lt;Link to={`/${params.section}/${x}`} className=&quot;pageLink&quot; key={x}&gt;{x}&lt;/Link&gt;);
    }
    
    return (
        &lt;div className=&quot;pageList&quot;&gt;
            {pageLinks}
        &lt;/div&gt;
    )
}

UPD. Codesandbox example
https://codesandbox.io/p/github/TheDanieLSh/React-Sites/draft/modest-hopper?layout=%257B%2522sidebarPanel%2522%253A%2522EXPLORER%2522%252C%2522rootPanelGroup%2522%253A%257B%2522direction%2522%253A%2522horizontal%2522%252C%2522type%2522%253A%2522PANEL_GROUP%2522%252C%2522id%2522%253A%2522ROOT_LAYOUT%2522%252C%2522panels%2522%253A%255B%257B%2522type%2522%253A%2522PANEL%2522%252C%2522panelType%2522%253A%2522TABS%2522%252C%2522id%2522%253A%2522cli1ipbjf00iu356lorpxfmbk%2522%257D%255D%252C%2522sizes%2522%253A%255B100%255D%257D%252C%2522tabbedPanels%2522%253A%257B%2522cli1ipbjf00iu356lorpxfmbk%2522%253A%257B%2522tabs%2522%253A%255B%257B%2522id%2522%253A%2522cli1ipbje00it356lhcqi48gt%2522%252C%2522mode%2522%253A%2522permanent%2522%252C%2522type%2522%253A%2522FILE%2522%252C%2522filepath%2522%253A%2522%252F.gitignore%2522%257D%255D%252C%2522id%2522%253A%2522cli1ipbjf00iu356lorpxfmbk%2522%252C%2522activeTabId%2522%253A%2522cli1ipbje00it356lhcqi48gt%2522%257D%257D%252C%2522showDevtools%2522%253Atrue%252C%2522showSidebar%2522%253Atrue%252C%2522sidebarPanelSize%2522%253A15%257D

答案1

得分: 1

The fetchProducts action is currently using a relative resource path for the products.json file it's fetching from the /public directory.

fetch("products.json")

This works when the app is on the root / route, but when navigating to sub-routes like /:section/:page_number, it requests "/figures/1/products" which doesn't exist in the public directory. To fix this, use an absolute resource path like "/products.json".

fetch("/products.json")

Here's the relevant code snippet:

export const fetchProducts = createAsyncThunk(
  "dataFetch/fetchProducts",
  async () => {
    const response = await fetch("/products.json");
    const data = await response.json();
    return data;
  }
);

Data fetching not happening when I use two parameters in React Router Dom and navigate directly on the page

英文:

The fetchProducts action is using a relative resource path for the products.json file it's fetching/loading from the &quot;/public&quot; directory.

fetch(&quot;products.json&quot;)

This works fine and as expected when the app is currently sitting on the root &quot;/&quot; route rendering the GoodsList component when is dispatches fetchProducts. The products.json resource is requested relative to the current URL path, e.g. &quot;/products.json&quot; and the data is loaded into the Redux store without issue.

Upon navigating to the sub-route, e.g. &quot;/:section/:page_number&quot;, the products.json file is now requested relative to that path, e.g. &quot;/figures/1/products&quot; which doesn't exist in the public directory. When the user is on a sub-route and reloads the page, the fetch just fails. This is fine so long as the user at least (eventually) lands on the main &quot;/&quot; page so when the request is made it actually succeeds.

To resolve you can simply specify an absolute resource path to &quot;/products.json&quot;.

fetch(&quot;/products.json&quot;)
export const fetchProducts = createAsyncThunk(
  &quot;dataFetch/fetchProducts&quot;,
  async () =&gt; {
    const response = await fetch(&quot;/products.json&quot;);
    const data = await response.json();
    return data;
  }
);

Data fetching not happening when I use two parameters in React Router Dom and navigate directly on the page

huangapple
  • 本文由 发表于 2023年5月22日 14:37:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76303554.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定