Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 如何处理react History.Push()导致不希望的组件重新装载?_Javascript_Reactjs_Typescript_React Router - Fatal编程技术网

Javascript 如何处理react History.Push()导致不希望的组件重新装载?

Javascript 如何处理react History.Push()导致不希望的组件重新装载?,javascript,reactjs,typescript,react-router,Javascript,Reactjs,Typescript,React Router,问题 在组件内部调用history.push()似乎会导致整个react组件卸载和重新装载;导致无意义的远程服务调用 具体地说,我有一个远程服务调用,在组件进入时触发。我不希望组件重新装载,也不希望服务调用重新运行(速度很慢) 它看起来像history.push(location.pathname+'?'+encodeURI(urlSearchParams.toString())都将导致卸载。我用错了吗?有没有更好的方法来跟踪用户过滤器更改的历史记录,而不必担心无关的服务调用 意图 我正在利用h

问题

在组件内部调用
history.push()
似乎会导致整个react组件卸载和重新装载;导致无意义的远程服务调用

具体地说,我有一个远程服务调用,在组件进入时触发。我不希望组件重新装载,也不希望服务调用重新运行(速度很慢)

它看起来像
history.push(location.pathname+'?'+encodeURI(urlSearchParams.toString())都将导致卸载。我用错了吗?有没有更好的方法来跟踪用户过滤器更改的历史记录,而不必担心无关的服务调用

意图

我正在利用
history.push()
来保持浏览器历史记录随查询参数的更改而更新。查询参数控制表数据的过滤,例如,sort=asc&isCompleted=true等

当用户更改其筛选设置时,我希望只对存储在状态中的现有表数据进行筛选,而不是远程重新加载数据并强迫用户坐着等待。我还希望一个用户能够共享一个URL到另一个用户与适当的过滤器包括在内

我尝试过的

  • 尝试完全删除history.push(),只使用state。这是可行的,但意味着不可能有一个可共享的URL,并将过滤器作为查询参数附加
  • 尝试修补useffect()和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>);

}

import React,{useffect,useState}来自“React”;
从“react router dom”导入{useLocation,useHistory};
函数useQuery(){
返回新的URLSearchParams(useLocation().search);
}
导出常量WidgetTable=()=>{
让urlSearchParams=useQuery();
让历史=使用历史();
让location=useLocation();
常量[originalTableData,setOriginalTableData]=使用状态(未定义);
常量[filteredTableData,setFilteredTableData]=useState(未定义);
//从远程服务获取表数据
const fetchTableData=async()=>{
}
//当用户在表上设置过滤器时触发(更新表中显示的数据)
常量filterTableData=()=>{
}
//当用户在表上设置过滤器时也会触发(更新浏览器中的URL)
常量setFilter=(filterToSet:ReleasePlanFilterType,值:string)=>{
开关(filterToSet){
案例发布计划筛选器类型。目标:{
if(urlSearchParams.get(filterToSet)){
urlSearchParams.set(filterToSet,值);
}否则{
追加(filterToSet,值);
}
打破
}
}
//我们已在查询参数中设置了过滤器,但将其保留到历史会导致重新加载:(
history.push(location.pathname+'?'+encodeURI(urlSearchParams.toString());
}
useffect(()=>{
fetchTableData();
}, []);
return(一个奇特的表和过滤控件);
}

在阅读了其他几个类似的堆栈溢出问题后,我发现似乎没有办法不重新装载(重新加载)组件。历史记录的更改会自动导致react router dom在引擎盖下处理事情的方式发生改变。我发现的大多数问题都是使用类组件,答案是使用shouldComponentUpdate来查看以前的路径是否等于新路径。如果它们相等,那么它们将返回,基本上是makin这样他们就不会重播了

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

所以现在的问题是将其转换为使用钩子。我需要运行一些测试,但我相信这应该适用于您的用例

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

通过添加
location.pathname
作为依赖项,只有当路径名实际更改时才应调用此效果。

经过数小时的调试后,我使用以下方法解决了此问题:

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

而不是:

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


这适用于
react router
v5。

使用location.pathname似乎无法按预期工作。是否可能由于类似的原因,上面或下面的组件会导致卸载?例如,如果父级也有用于位置的道具,它是否也会触发卸载?@Ray发生了什么事情,但它似乎没有按预期工作?我通过codesandbox尝试了一个简单的示例,它似乎正在工作。您的示例似乎也正常工作。可能还有其他组件对此进行包装,从而导致卸载/重新装载。您是否能够提供带有包装组件的codesandbox?有效地获得相同的行为,更改筛选器和d调用历史记录。push()激发useEffect,即使按所述设置了location.pathname。此组件有好几层-可能是父组件之一存在问题。是否有方法诊断父组件之一是否可疑?几个父组件也使用历史记录。我可以尝试在沙盒中复制它,但我需要一些是时候理清“特定工作”的界限了代码。经过一番探索,我发现一个父组件正在使用component='widgetable'。将其切换到render,再加上您建议的更改,现在会产生正确的行为!太棒了!很高兴您能让它正常工作。我不久前就要向您发送我的Codesandbox,但召开了一次会议。我确认这也是我看到的。有什么想法吗为什么会这样?我相信这是图书馆里的一个错误。