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,但召开了一次会议。我确认这也是我看到的。有什么想法吗为什么会这样?我相信这是图书馆里的一个错误。