![](/img/trans.png)
[英]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.