无法使用react-router-dom Link重置状态

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

Unable to reset the state using react-router-dom Link

问题

我有一个SearchBar组件,其中包含一个Link,当单击它时,会跳转到一个显示与特定类别相关的一组产品的ProductSearchScreen

return (
  <Link to={{ pathname:某个路径, search: `searchItem=${category.name}` }}>
    {category.name}
  </Link>
)

在我的ProductSearchScreen中,我有复选框,用于筛选数据,如“类别”、“品牌”筛选等...

例如,要筛选类别,我有以下代码

const [selectedCategories, setSelectedCategories] = useState(queryParams.get('categories')?.split(',') ?? []);

<input
  type="checkbox"
  checked={selectedCategories.includes(category)}
  onClick={() => handleCategories(category)}
/>

问题是,假设我在category1ProductSearchScreen中,有一些复选框被选中,然后在搜索栏中键入category2并导航到category2页面,那么复选框仍然保持为checked状态,用于category2

尽管在导航时我没有在queryParams中找到任何内容,但它不会重置selectedCategories状态。
如何确保导航到另一页时复选框不被选中?

编辑:
这是使用路径和查询字符串的组件

function ProductSearchScreen() {
    const [products, setProducts] = useState([]);
    const [queryParams] = useSearchParams();

    // 这是我获取的查询字符串
    const category = queryParams.get('searchItem'); 
    const categories = queryParams.get('categories')?.split(',');
    const uniqueCategories = getUniqueCategories(products)

    // 通过axios调用,我获取产品列表并更新状态如setProducts(products)。

    // 这是用于筛选类别的辅助函数
    const filterCategories = (product) => {
        if(categories?.length > 0) {
            return categories?.includes(product.category);
        } else {
            return product
        }
    }

    const filteredAndSortedProducts = products?.filter(filterCategories)

    return ( <Filters uniqueCategories={uniqueCategories}/> )
}
function Filters({ uniqueCategories }) {
    const [queryParams, setQueryParams] = useSearchParams();
    const [selectedCategories, setSelectedCategories] = useState(queryParams.get('categories')?.split(',') ?? []);

    const handleCategories = (category) => {
        if (selectedCategories.includes(category)) {
            setSelectedCategories(selectedCategories.filter((c) => c !== category));
        } else {
            setSelectedCategories([...selectedCategories, category]);
        }
    }

    return (
        <div key={index} className="filter-type">
            <input
                type="checkbox"
                disabled={queryParams.get('categories')?.split(',').includes(category)}
                checked={selectedCategories.includes(category)}
                onChange={() => handleCategories(category)}
            />
            <div className="filter-item">{category}</div>
        </div>
    )
}
英文:

I have a SearchBar component where I have this Link which on click takes me to a ProductSearchScreen which display a set of products associated with a category.

return (
  &lt;Link to={{ pathname:# somepath, search: `searchItem=${category.name}` }}&gt;
    {category.name}
  &lt;/Link&gt;
)

In my ProductSearchScreen, I have checkboxes which filter out the data such as "category", "brand" filter etc...

For filtering out categories for example, I have this code

const [selectedCategories, setSelectedCategories] = useState(queryParams.get(&#39;categories&#39;)?.split(&#39;,&#39;) ?? []);

&lt;input
  type=&quot;checkbox&quot;
  checked={selectedCategories.includes(category)}
  onClick={() =&gt; handleCategories(category)}
/&gt;

The issue is, suppose I'm in ProductSearchScreen of category1 and have few checkboxes clicked and in searchBar I type category2 and navigate to category2 page, the checkboxes still remain checked for category2.

Though I don't have anything in queryParams on navigate, it is not resetting the state of selectedCategories.
How can I make sure the checkboxes are not checked on navigating to another page?

Edit:
This is the component consuming the path and querystring

function ProductSearchScreen() {
    const [products, setProducts] = useState([]);
    const [queryParams] = useSearchParams();

    // Here is the queryString i am getting
    const category = queryParams.get(&#39;searchItem&#39;); 
    const categories = queryParams.get(&#39;categories&#39;)?.split(&#39;,&#39;);
    const uniqueCategories = getUniqueCategories(products)

    // with axios call, i get the list of products and update the state like setProducts(products).

    // This is a helper function to filter the categories
    const filterCategories = (product) =&gt; {
        if(categories?.length &gt; 0) {
            return categories?.includes(product.category);
        } else {
            return product
        }
    }

    const filteredAndSortedProducts = products?.filter(filterCategories)

    return ( &lt;Filters uniqueCategories={uniqueCategories}/&gt; )
}
function Filters({ uniqueCategories }) {
    const [queryParams, setQueryParams] = useSearchParams();
    const [selectedCategories, setSelectedCategories] = useState(queryParams.get(&#39;categories&#39;)?.split(&#39;,&#39;) ?? []);

    const handleCategories = (category) =&gt; {
        if (selectedCategories.includes(category)) {
            setSelectedCategories(selectedCategories.filter((c) =&gt; c !== category));
        } else {
            setSelectedCategories([...selectedCategories, category]);
        }
    }

    return (
        &lt;div key={index} className=&quot;filter-type&quot;&gt;
            &lt;input
                type=&quot;checkbox&quot;
                disabled={queryParams.get(&#39;categories&#39;)?.split(&#39;,&#39;).includes(category)}
                checked={selectedCategories.includes(category)}
                onChange={() =&gt; handleCategories(category)}
            /&gt;
            &lt;div className=&quot;filter-item&quot;&gt;{category}&lt;/div&gt;
        &lt;/div&gt;
    )
}

答案1

得分: 1

Filters 组件只在挂载时检查查询参数一次。如果需要对“categories”查询参数的更改作出反应,还应该实现一个生命周期钩子,例如useEffect,以更新selectedCategories

function Filters({ uniqueCategories }) {
  const [queryParams, setQueryParams] = useSearchParams();
  const categories = queryParams.get('categories');

  const [selectedCategories, setSelectedCategories] = useState(categories?.split(',') ?? []);

  useEffect(() => {
    setSelectedCategories(categories?.split(',') ?? []);
  }, [categories]);

  ...

  return (
    ...
  );
}

请注意,当您发现自己写了一个useState/useEffect组合时,您可能实际上只需要useMemo钩子。

function Filters({ uniqueCategories }) {
  const [queryParams, setQueryParams] = useSearchParams();
  const categories = queryParams.get('categories');

  const selectedCategories = useMemo(() => {
    return categories?.split(',') ?? [];
  }, [categories]);

  ...

  return (
    ...
  );
}
英文:

The Filters component only checks the query params once when it mounts. If it needs to react to changes in the &quot;categories&quot; query params then it should also implement a lifecycle hook, e.g. useEffect, to update the selectedCategories.

function Filters({ uniqueCategories }) {
  const [queryParams, setQueryParams] = useSearchParams();
  const categories = queryParams.get(&#39;categories&#39;);

  const [selectedCategories, setSelectedCategories] = useState(categories?.split(&#39;,&#39;) ?? []);

  useEffect(() =&gt; {
    setSelectedCategories(categories?.split(&#39;,&#39;) ?? []);
  }, [categories]);

  ...

  return (
    ...
  );
}

Note that when you see that you've written a useState/useEffect combo that you may actually just need the useMemo hook.

function Filters({ uniqueCategories }) {
  const [queryParams, setQueryParams] = useSearchParams();
  const categories = queryParams.get(&#39;categories&#39;);

  const selectedCategories = useMemo(() =&gt; {
    return categories?.split(&#39;,&#39;) ?? [];
  }, [categories]);

  ...

  return (
    ...
  );
}

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

发表评论

匿名网友

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

确定