[英]React Router: How to redirect to a different component when a link/button is clicked?
[英]React Router - How to prevent top level refresh when child component button is clicked, preventDefault does not seem to make a difference
背景:
我有一个简单的反应路由器:
<BrowserRouter >
<Routes>
<Route path="test/:locationId" element={<TestComponent />}></Route>
然后我的组件非常简单:
function Inner(props) {
let ele = JSON.stringify(props);
console.log(" this is inner , with " + ele);
const [value, setValue] = useState(parseInt(ele));
return (
<div onClick={(e) => e.stopPropagation()}>
<p> Inner component: {String(ele)}</p>
<button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
console.log("inner btn clicked for " + value);
setValue(value + 1);
}}
>
{" "}
inner btn with clicked value {value}
</button>
</div>
);
}
export default function TestComponent(props) {
console.log("TestComponent top level component " + new Date());
console.log("I will do some heavy work like a big http request.....")
const [res, setRes] = useState([1, 2, 3]);
let params = useParams();
console.dir(params);
if (res.length > 0) {
console.log("res > 0 ");
return (
<div className="container">
{res.map((ele) => {
return <div key={String(ele)}>{Inner(ele)}</div>;
})}
</div>
);
}
问题:每当我单击 3 个按钮中的任何一个时,我都会看到TestComponent
从顶层刷新,就像TestComponent top level component Mon Jul 18 2022 17:35:52 GMT-0400 (Eastern Daylight Time)
。
现在我计划在TestComponent
中执行一些繁重的 http 请求和 setState() 。 但是,每当我单击按钮(在子组件中)时,此TestComponent
总是会刷新,因此会一遍又一遍地执行我想要阻止的 http 请求。 尝试了 e.stopPropagation() 和 e.preventDefault() 但没有发现任何区别。 在此处输入图像描述
您似乎没有很好地理解 React 组件的生命周期,并且使用了完全错误的工具来测量 React 渲染。
所有控制台日志都在渲染周期之外作为无意的副作用发生。 这意味着任何时候 React 调用您的应用程序(整个应用程序代码)以重新渲染(出于任何原因)组件主体在“渲染阶段”期间执行,以便计算更改和实际需要推送的差异在“提交阶段”期间到 DOM。 提交阶段是 React 将应用程序渲染到 DOM,这就是我们通常俗称的 React 组件渲染。
请注意,“渲染阶段”被认为是一个纯函数,可以在任何 React 需要调用它时调用。 这就是为什么它是纯功能,即没有无意的副作用。 React 函数组件的整个函数体就是“render”方法。
请注意,“提交阶段”是 UI 已更新到 DOM 并且现在可以运行效果的地方。
在组件生命周期之外使用console.log
的问题通常会因为我们将应用程序渲染到React.StrictMode
组件中而加剧,该组件会双重安装应用程序/组件以确保可重用状态,并有意双重调用某些方法和用作检测无意副作用的一种方式。
Inner
像 React 组件一样定义,但像常规函数一样手动调用。 这是一个相当明显的禁忌。 在 React 中,我们将 React 组件的引用作为 JSX传递给 React。 我们从不直接直接调用我们的 React 函数。
console.log
语句移动到useEffect
钩子中,以便在每个渲染(到 DOM )周期中准确调用它们一次。 所有有意的副作用都应该从useEffect
挂钩中完成。Inner
渲染为 React 组件并正确地将 props 传递给它。例子:
function Inner({ ele }) {
useEffect(() => {
console.log("this is inner , with " + ele);
});
const [value, setValue] = useState(ele);
return (
<div onClick={(e) => e.stopPropagation()}>
<p>Inner component: {String(ele)}</p>
<button
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
console.log("inner btn clicked for " + value);
setValue(value + 1);
}}
>
inner btn with clicked value {value}
</button>
</div>
);
}
...
function TestComponent(props) {
const [res, setRes] = useState([1, 2, 3]);
let params = useParams();
useEffect(() => {
console.log("TestComponent top level component " + new Date());
console.log("I will do some heavy work like a big http request.....");
console.dir(params);
if (res.length > 0) {
console.log("res > 0 ");
}
});
if (res.length > 0) {
return (
<div className="container">
{res.map((ele) => (
<div key={ele}>
<Inner {...{ ele }} />
</div>
))}
</div>
);
}
}
...
<Routes>
<Route path="test/:locationId" element={<TestComponent />} />
</Routes>
请注意,在初始StrictMode
挂载/重新挂载之后,单击按钮只会记录来自每个Inner
组件的单个日志。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.