簡體   English   中英

如何處理導致不需要的組件重新安裝的反應 History.Push()?

[英]How to handle react History.Push() causing undesired component remounts?

問題

在組件內部調用history.push()似乎會導致整個 react 組件卸載和重新安裝; 導致毫無意義的遠程服務調用。

具體來說,我有一個在組件條目上觸發的遠程服務調用。 我不希望組件重新安裝,也不希望服務調用重新運行(它很慢)。

好像history.push(location.pathname + '?' + encodeURI(urlSearchParams.toString())); 無論如何都會導致卸載。 我使用不正確嗎? 是否有更好的方法來跟蹤用戶過濾器更改的歷史,而不必擔心無關的服務調用?

意圖

我正在利用history.push()來保持瀏覽器歷史記錄隨着查詢參數的更改而更新。 查詢參數控制表數據的過濾,例如?sort=asc&isCompleted=true等。

當用戶更改過濾設置時,我打算對存儲在 state 中的現有表數據進行簡單過濾,而不是遠程重新加載數據並強迫用戶坐等。 我還希望用戶能夠與包含適當過濾器的其他用戶共享 URL。

我試過的

  • 嘗試完全刪除 history.push(),僅使用 state。 這可行,但意味着不可能有一個可共享的 URL 並將過濾器附加為查詢參數。
  • 嘗試修改 useEffect() 和 useRef() 但對不斷的重新安裝感到沮喪。

組件代碼

import React, { useEffect, useState } from 'react';
import { useLocation, useHistory } from 'react-router-dom';

function useQuery() {
  return new URLSearchParams(useLocation().search);
}

export const WidgetTable = () => {
  let urlSearchParams = useQuery();
  let history = useHistory();
  let location = useLocation();

  const [originalTableData, setOriginalTableData] = useState<TableData| undefined>(undefined);
  const [filteredTableData, setFilteredTableData] = useState<TableData| undefined>(undefined);

  // go get the table data from the remote service
  const fetchTableData = async () => {
   <- go remotely fetch table data and then set originalTableData ->
  }

  // triggered when a user sets a filter on the table (updates the data displayed in the table)
  const filterTableData = () => {
   <- filter the existing table data in state and then set the filterdTableData ->
  }

  // also triggered when a user sets a filter on the table (updates the URL in the browser)
  const setFilter = (filterToSet: ReleasePlanFilterType, value: string) => {
    switch (filterToSet) {
      case ReleasePlanFilterType.Target: {
        if (urlSearchParams.get(filterToSet)) {
          urlSearchParams.set(filterToSet, value);
        } else {
          urlSearchParams.append(filterToSet, value);
        }
        break;
      }
      <snip>
    }

   // We've set the filter in the query params, but persisting this to the history causes a reload :(
   history.push(location.pathname + '?' + encodeURI(urlSearchParams.toString())); 
  
  }

  useEffect(() => {
    fetchTableData();
  }, []);

  return (<snip> a fancy table and filtering controls <snip>);

}

據我所知,在閱讀了其他幾個類似的堆棧溢出問題之后,似乎沒有辦法不重新安裝(重新渲染)組件。 歷史更改會自動導致 react 路由器 dom 如何處理幕后事務的 prop 更改。 我發現這些問題中的大多數都使用了 class 組件,答案是使用 shouldComponentUpdate 來查看以前的路徑是否等於新路徑。 如果他們是平等的,那么他們就會回來,基本上是這樣他們就不會重新渲染。

shouldComponentUpdate: function(nextProps, nextState) {
  if(this.props.route.path == nextProps.route.path) return false;
  return true;
}

來源: 防止 react-router history.push 重新加載當前路線

所以現在的問題是將其轉換為使用鈎子。 我需要運行一些測試,但我相信這應該適用於您的用例。

useEffect(() => {
    fetchTableData();
}, [location.pathname]);

通過將location.pathname添加為依賴項,只有在路徑名實際更改時才應調用此效果。

經過數小時的調試,我設法通過使用以下方法解決了這個問題:

<Route exact path="/">
  <Home />
</Route>

代替:

<Route exact path="/" component={Home} />

這適用於react-router v5。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM