[{"data":1,"prerenderedAt":1493},["ShallowReactive",2],{"blog-\u002Fblog\u002Freact-navigation-hooks-guide":3},{"id":4,"title":5,"body":6,"description":1478,"difficulty":1479,"extension":1480,"framework":1481,"frameworkSlug":1482,"meta":1483,"navigation":136,"order":133,"path":1484,"qaPath":1485,"seo":1486,"stem":1487,"subtopic":1488,"topic":1489,"topicSlug":1490,"updated":1491,"__hash__":1492},"blog\u002Fblog\u002Freact-navigation-hooks-guide.md","React Router v6 Navigation Hooks — Complete Interview Guide",{"type":7,"value":8,"toc":1470},"minimark",[9,14,30,56,60,86,255,274,289,306,310,335,340,446,550,560,564,593,711,722,929,942,956,960,972,1086,1110,1130,1340,1354,1358,1466],[10,11,13],"h2",{"id":12},"why-navigation-hooks-matter-in-interviews","Why Navigation Hooks Matter in Interviews",[15,16,17,18,22,23,22,26,29],"p",{},"React Router v6 replaced the v5 component-centric API (",[19,20,21],"code",{},"\u003CRedirect>",", ",[19,24,25],{},"useHistory",[19,27,28],{},"useRouteMatch",") with a focused set of hooks. Interviewers test navigation hooks because they expose whether a candidate understands the browser History API, controlled state vs. URL state, and the lifecycle of a navigation event inside a React app. Getting these wrong in production means broken Back buttons, unshareable filter URLs, or infinite render loops — all high-visibility bugs.",[15,31,32,33,36,37,40,41,44,45,48,49,40,52,55],{},"The hooks are composable building blocks. ",[19,34,35],{},"useNavigate"," handles imperative redirects. ",[19,38,39],{},"useParams"," and ",[19,42,43],{},"useLocation"," read the current URL. ",[19,46,47],{},"useSearchParams"," manages the query string as first-class state. ",[19,50,51],{},"useMatch",[19,53,54],{},"useBlocker"," cover edge cases that trip up even senior engineers. Knowing when to reach for each one — and the sharp edges around each — is what separates a strong answer from a vague one.",[10,57,59],{"id":58},"usenavigate-push-replace-back-and-state","useNavigate — push, replace, back, and state",[15,61,62,65,66,69,70,73,74,77,78,81,82,85],{},[63,64,35],"strong",{}," returns a ",[19,67,68],{},"navigate"," function. The most common call is ",[19,71,72],{},"navigate('\u002Fpath')",", which ",[63,75,76],{},"pushes"," a new entry onto the history stack so the user can press Back. Passing ",[19,79,80],{},"{ replace: true }"," ",[63,83,84],{},"replaces"," the current entry — correct after a login redirect so the user can't press Back into the login form.",[87,88,93],"pre",{"className":89,"code":90,"language":91,"meta":92,"style":92},"language-jsx shiki shiki-themes github-light github-dark","function LoginPage() {\n  const navigate = useNavigate();\n\n  async function handleSubmit(e) {\n    e.preventDefault();\n    await authenticateUser(credentials);\n    \u002F\u002F replace: true — login page should not be reachable via Back after success\n    navigate('\u002Fdashboard', { replace: true });\n  }\n\n  return \u003Cform onSubmit={handleSubmit}>...\u003C\u002Fform>;\n}\n","jsx","",[19,94,95,112,131,138,160,171,183,190,211,217,222,249],{"__ignoreMap":92},[96,97,100,104,108],"span",{"class":98,"line":99},"line",1,[96,101,103],{"class":102},"szBVR","function",[96,105,107],{"class":106},"sScJk"," LoginPage",[96,109,111],{"class":110},"sVt8B","() {\n",[96,113,115,118,122,125,128],{"class":98,"line":114},2,[96,116,117],{"class":102},"  const",[96,119,121],{"class":120},"sj4cs"," navigate",[96,123,124],{"class":102}," =",[96,126,127],{"class":106}," useNavigate",[96,129,130],{"class":110},"();\n",[96,132,134],{"class":98,"line":133},3,[96,135,137],{"emptyLinePlaceholder":136},true,"\n",[96,139,141,144,147,150,153,157],{"class":98,"line":140},4,[96,142,143],{"class":102},"  async",[96,145,146],{"class":102}," function",[96,148,149],{"class":106}," handleSubmit",[96,151,152],{"class":110},"(",[96,154,156],{"class":155},"s4XuR","e",[96,158,159],{"class":110},") {\n",[96,161,163,166,169],{"class":98,"line":162},5,[96,164,165],{"class":110},"    e.",[96,167,168],{"class":106},"preventDefault",[96,170,130],{"class":110},[96,172,174,177,180],{"class":98,"line":173},6,[96,175,176],{"class":102},"    await",[96,178,179],{"class":106}," authenticateUser",[96,181,182],{"class":110},"(credentials);\n",[96,184,186],{"class":98,"line":185},7,[96,187,189],{"class":188},"sJ8bj","    \u002F\u002F replace: true — login page should not be reachable via Back after success\n",[96,191,193,196,198,202,205,208],{"class":98,"line":192},8,[96,194,195],{"class":106},"    navigate",[96,197,152],{"class":110},[96,199,201],{"class":200},"sZZnC","'\u002Fdashboard'",[96,203,204],{"class":110},", { replace: ",[96,206,207],{"class":120},"true",[96,209,210],{"class":110}," });\n",[96,212,214],{"class":98,"line":213},9,[96,215,216],{"class":110},"  }\n",[96,218,220],{"class":98,"line":219},10,[96,221,137],{"emptyLinePlaceholder":136},[96,223,225,228,231,235,238,241,244,246],{"class":98,"line":224},11,[96,226,227],{"class":102},"  return",[96,229,230],{"class":110}," \u003C",[96,232,234],{"class":233},"s9eBZ","form",[96,236,237],{"class":106}," onSubmit",[96,239,240],{"class":102},"=",[96,242,243],{"class":110},"{handleSubmit}>...\u003C\u002F",[96,245,234],{"class":233},[96,247,248],{"class":110},">;\n",[96,250,252],{"class":98,"line":251},12,[96,253,254],{"class":110},"}\n",[15,256,257,258,261,262,265,266,269,270,273],{},"Pass an ",[63,259,260],{},"integer"," to move through history: ",[19,263,264],{},"navigate(-1)"," goes back one step, ",[19,267,268],{},"navigate(1)"," goes forward. Always prefer this over ",[19,271,272],{},"window.history.back()"," — the native call bypasses React Router's blockers and transition listeners.",[15,275,276,277,280,281,284,285,288],{},"You can attach ",[63,278,279],{},"state"," to any navigation: ",[19,282,283],{},"navigate('\u002Fcheckout', { state: { productId: 42 } })",". The state is stored in the History API entry and read on the destination via ",[19,286,287],{},"useLocation().state",". It is invisible in the URL and disappears on a hard refresh, so treat it as a session-only hint rather than durable data.",[15,290,291,294,295,298,299,301,302,305],{},[63,292,293],{},"Critical interview trap:"," calling ",[19,296,297],{},"navigate()"," during render (outside a handler or effect) triggers an immediate re-render loop and the React warning about updating a component while rendering another. Always put ",[19,300,68],{}," calls inside event handlers or ",[19,303,304],{},"useEffect",".",[10,307,309],{"id":308},"useparams-and-uselocation","useParams and useLocation",[15,311,312,314,315,318,319,322,323,326,327,330,331,334],{},[63,313,39],{}," returns an object keyed by the dynamic segments declared in your route path. For ",[19,316,317],{},"\u003CRoute path=\"\u002Fusers\u002F:userId\u002Fposts\u002F:postId\">",", the component gets ",[19,320,321],{},"{ userId, postId }"," — both as ",[63,324,325],{},"strings",". Always parse numbers before arithmetic (",[19,328,329],{},"Number(params.postId)",") and guard against ",[19,332,333],{},"undefined"," for optional segments.",[15,336,337,339],{},[63,338,43],{}," returns the full current location object:",[341,342,343,359],"table",{},[344,345,346],"thead",{},[347,348,349,353,356],"tr",{},[350,351,352],"th",{},"Field",[350,354,355],{},"Example",[350,357,358],{},"Notes",[360,361,362,378,396,414,431],"tbody",{},[347,363,364,370,375],{},[365,366,367],"td",{},[19,368,369],{},"pathname",[365,371,372],{},[19,373,374],{},"\u002Fproducts\u002F42",[365,376,377],{},"The path without query or hash",[347,379,380,385,390],{},[365,381,382],{},[19,383,384],{},"search",[365,386,387],{},[19,388,389],{},"?sort=price&page=2",[365,391,392,393],{},"Raw query string including ",[19,394,395],{},"?",[347,397,398,403,408],{},[365,399,400],{},[19,401,402],{},"hash",[365,404,405],{},[19,406,407],{},"#reviews",[365,409,410,411],{},"Fragment including ",[19,412,413],{},"#",[347,415,416,420,425],{},[365,417,418],{},[19,419,279],{},[365,421,422],{},[19,423,424],{},"{ from: '\u002Fcart' }",[365,426,427,428,430],{},"Attached by ",[19,429,297],{},"; lost on refresh",[347,432,433,438,443],{},[365,434,435],{},[19,436,437],{},"key",[365,439,440],{},[19,441,442],{},"'abc123'",[365,444,445],{},"Unique per history entry",[87,447,449],{"className":89,"code":448,"language":91,"meta":92,"style":92},"function BreadcrumbBack() {\n  const { state } = useLocation();\n  const navigate = useNavigate();\n  \u002F\u002F Graceful fallback if the user arrived via a direct URL (state is undefined)\n  const back = state?.returnPath ?? '\u002F';\n  return \u003Cbutton onClick={() => navigate(back)}>← Back\u003C\u002Fbutton>;\n}\n",[19,450,451,460,479,491,496,517,546],{"__ignoreMap":92},[96,452,453,455,458],{"class":98,"line":99},[96,454,103],{"class":102},[96,456,457],{"class":106}," BreadcrumbBack",[96,459,111],{"class":110},[96,461,462,464,467,469,472,474,477],{"class":98,"line":114},[96,463,117],{"class":102},[96,465,466],{"class":110}," { ",[96,468,279],{"class":120},[96,470,471],{"class":110}," } ",[96,473,240],{"class":102},[96,475,476],{"class":106}," useLocation",[96,478,130],{"class":110},[96,480,481,483,485,487,489],{"class":98,"line":133},[96,482,117],{"class":102},[96,484,121],{"class":120},[96,486,124],{"class":102},[96,488,127],{"class":106},[96,490,130],{"class":110},[96,492,493],{"class":98,"line":140},[96,494,495],{"class":188},"  \u002F\u002F Graceful fallback if the user arrived via a direct URL (state is undefined)\n",[96,497,498,500,503,505,508,511,514],{"class":98,"line":162},[96,499,117],{"class":102},[96,501,502],{"class":120}," back",[96,504,124],{"class":102},[96,506,507],{"class":110}," state?.returnPath ",[96,509,510],{"class":102},"??",[96,512,513],{"class":200}," '\u002F'",[96,515,516],{"class":110},";\n",[96,518,519,521,523,526,529,531,534,537,539,542,544],{"class":98,"line":173},[96,520,227],{"class":102},[96,522,230],{"class":110},[96,524,525],{"class":233},"button",[96,527,528],{"class":106}," onClick",[96,530,240],{"class":102},[96,532,533],{"class":110},"{() ",[96,535,536],{"class":102},"=>",[96,538,121],{"class":106},[96,540,541],{"class":110},"(back)}>← Back\u003C\u002F",[96,543,525],{"class":233},[96,545,248],{"class":110},[96,547,548],{"class":98,"line":185},[96,549,254],{"class":110},[15,551,552,553,556,557,559],{},"Put ",[19,554,555],{},"location"," in ",[19,558,304],{}," dependency arrays to re-run logic whenever the user navigates — this is the correct pattern for analytics page-view tracking.",[10,561,563],{"id":562},"usesearchparams-reading-and-writing-query-strings","useSearchParams — reading and writing query strings",[15,565,566,568,569,572,573,576,577,580,581,584,585,588,589,592],{},[63,567,47],{}," is to query strings what ",[19,570,571],{},"useState"," is to component state — it returns ",[19,574,575],{},"[searchParams, setSearchParams]",". The ",[19,578,579],{},"searchParams"," value is a live ",[63,582,583],{},"URLSearchParams"," instance; call ",[19,586,587],{},".get('key')"," for a single value or ",[19,590,591],{},".getAll('key')"," for repeated keys.",[87,594,596],{"className":89,"code":595,"language":91,"meta":92,"style":92},"function ProductList() {\n  const [searchParams] = useSearchParams();\n  const category = searchParams.get('category') ?? 'all'; \u002F\u002F null → 'all'\n  const page = Number(searchParams.get('page') ?? '1');\n  return \u003Cp>{category} — page {page}\u003C\u002Fp>;\n}\n",[19,597,598,607,626,660,692,707],{"__ignoreMap":92},[96,599,600,602,605],{"class":98,"line":99},[96,601,103],{"class":102},[96,603,604],{"class":106}," ProductList",[96,606,111],{"class":110},[96,608,609,611,614,616,619,621,624],{"class":98,"line":114},[96,610,117],{"class":102},[96,612,613],{"class":110}," [",[96,615,579],{"class":120},[96,617,618],{"class":110},"] ",[96,620,240],{"class":102},[96,622,623],{"class":106}," useSearchParams",[96,625,130],{"class":110},[96,627,628,630,633,635,638,641,643,646,649,651,654,657],{"class":98,"line":133},[96,629,117],{"class":102},[96,631,632],{"class":120}," category",[96,634,124],{"class":102},[96,636,637],{"class":110}," searchParams.",[96,639,640],{"class":106},"get",[96,642,152],{"class":110},[96,644,645],{"class":200},"'category'",[96,647,648],{"class":110},") ",[96,650,510],{"class":102},[96,652,653],{"class":200}," 'all'",[96,655,656],{"class":110},"; ",[96,658,659],{"class":188},"\u002F\u002F null → 'all'\n",[96,661,662,664,667,669,672,675,677,679,682,684,686,689],{"class":98,"line":140},[96,663,117],{"class":102},[96,665,666],{"class":120}," page",[96,668,124],{"class":102},[96,670,671],{"class":106}," Number",[96,673,674],{"class":110},"(searchParams.",[96,676,640],{"class":106},[96,678,152],{"class":110},[96,680,681],{"class":200},"'page'",[96,683,648],{"class":110},[96,685,510],{"class":102},[96,687,688],{"class":200}," '1'",[96,690,691],{"class":110},");\n",[96,693,694,696,698,700,703,705],{"class":98,"line":162},[96,695,227],{"class":102},[96,697,230],{"class":110},[96,699,15],{"class":233},[96,701,702],{"class":110},">{category} — page {page}\u003C\u002F",[96,704,15],{"class":233},[96,706,248],{"class":110},[96,708,709],{"class":98,"line":173},[96,710,254],{"class":110},[15,712,713,714,717,718,721],{},"When writing, the ",[63,715,716],{},"callback form"," of ",[19,719,720],{},"setSearchParams"," is the safe default because it receives the current params and lets you mutate a copy without losing other keys:",[87,723,725],{"className":89,"code":724,"language":91,"meta":92,"style":92},"function SortControl() {\n  const [searchParams, setSearchParams] = useSearchParams();\n\n  function handleSort(field) {\n    setSearchParams(\n      prev => {\n        const next = new URLSearchParams(prev); \u002F\u002F clone\n        next.set('sort', field);  \u002F\u002F update one key\n        next.delete('page');      \u002F\u002F reset pagination when sort changes\n        return next;\n      },\n      { replace: true } \u002F\u002F don't add a history entry on every sort toggle\n    );\n  }\n\n  return \u003Cbutton onClick={() => handleSort('price')}>Sort by price\u003C\u002Fbutton>;\n}\n",[19,726,727,736,756,760,775,783,794,816,835,852,860,865,877,883,888,893,924],{"__ignoreMap":92},[96,728,729,731,734],{"class":98,"line":99},[96,730,103],{"class":102},[96,732,733],{"class":106}," SortControl",[96,735,111],{"class":110},[96,737,738,740,742,744,746,748,750,752,754],{"class":98,"line":114},[96,739,117],{"class":102},[96,741,613],{"class":110},[96,743,579],{"class":120},[96,745,22],{"class":110},[96,747,720],{"class":120},[96,749,618],{"class":110},[96,751,240],{"class":102},[96,753,623],{"class":106},[96,755,130],{"class":110},[96,757,758],{"class":98,"line":133},[96,759,137],{"emptyLinePlaceholder":136},[96,761,762,765,768,770,773],{"class":98,"line":140},[96,763,764],{"class":102},"  function",[96,766,767],{"class":106}," handleSort",[96,769,152],{"class":110},[96,771,772],{"class":155},"field",[96,774,159],{"class":110},[96,776,777,780],{"class":98,"line":162},[96,778,779],{"class":106},"    setSearchParams",[96,781,782],{"class":110},"(\n",[96,784,785,788,791],{"class":98,"line":173},[96,786,787],{"class":155},"      prev",[96,789,790],{"class":102}," =>",[96,792,793],{"class":110}," {\n",[96,795,796,799,802,804,807,810,813],{"class":98,"line":185},[96,797,798],{"class":102},"        const",[96,800,801],{"class":120}," next",[96,803,124],{"class":102},[96,805,806],{"class":102}," new",[96,808,809],{"class":106}," URLSearchParams",[96,811,812],{"class":110},"(prev); ",[96,814,815],{"class":188},"\u002F\u002F clone\n",[96,817,818,821,824,826,829,832],{"class":98,"line":192},[96,819,820],{"class":110},"        next.",[96,822,823],{"class":106},"set",[96,825,152],{"class":110},[96,827,828],{"class":200},"'sort'",[96,830,831],{"class":110},", field);  ",[96,833,834],{"class":188},"\u002F\u002F update one key\n",[96,836,837,839,842,844,846,849],{"class":98,"line":213},[96,838,820],{"class":110},[96,840,841],{"class":106},"delete",[96,843,152],{"class":110},[96,845,681],{"class":200},[96,847,848],{"class":110},");      ",[96,850,851],{"class":188},"\u002F\u002F reset pagination when sort changes\n",[96,853,854,857],{"class":98,"line":219},[96,855,856],{"class":102},"        return",[96,858,859],{"class":110}," next;\n",[96,861,862],{"class":98,"line":224},[96,863,864],{"class":110},"      },\n",[96,866,867,870,872,874],{"class":98,"line":251},[96,868,869],{"class":110},"      { replace: ",[96,871,207],{"class":120},[96,873,471],{"class":110},[96,875,876],{"class":188},"\u002F\u002F don't add a history entry on every sort toggle\n",[96,878,880],{"class":98,"line":879},13,[96,881,882],{"class":110},"    );\n",[96,884,886],{"class":98,"line":885},14,[96,887,216],{"class":110},[96,889,891],{"class":98,"line":890},15,[96,892,137],{"emptyLinePlaceholder":136},[96,894,896,898,900,902,904,906,908,910,912,914,917,920,922],{"class":98,"line":895},16,[96,897,227],{"class":102},[96,899,230],{"class":110},[96,901,525],{"class":233},[96,903,528],{"class":106},[96,905,240],{"class":102},[96,907,533],{"class":110},[96,909,536],{"class":102},[96,911,767],{"class":106},[96,913,152],{"class":110},[96,915,916],{"class":200},"'price'",[96,918,919],{"class":110},")}>Sort by price\u003C\u002F",[96,921,525],{"class":233},[96,923,248],{"class":110},[96,925,927],{"class":98,"line":926},17,[96,928,254],{"class":110},[15,930,931,932,934,935,938,939,941],{},"Passing a plain object to ",[19,933,720],{}," replaces ",[63,936,937],{},"all"," params — a common bug when a developer only wants to change one key. The second argument ",[19,940,80],{}," prevents the Back button from unwinding each individual filter click, which is almost always the right UX for search\u002Ffilter controls.",[15,943,944,952,953,955],{},[63,945,946,947,949,950],{},"Choose ",[19,948,47],{}," over ",[19,951,571],{}," whenever the filter values need to survive a refresh, be shareable via URL, or be indexable by search engines. Reserve ",[19,954,571],{}," for purely visual, ephemeral UI state.",[10,957,959],{"id":958},"usematch-and-useblocker","useMatch and useBlocker",[15,961,962,964,965,968,969,305],{},[63,963,51],{}," tests the current URL against a pattern and returns a match object or ",[19,966,967],{},"null",". Its main use case is conditional styling — highlighting an active nav section without relying on ",[19,970,971],{},"\u003CNavLink>",[87,973,975],{"className":89,"code":974,"language":91,"meta":92,"style":92},"function SettingsLink() {\n  \u002F\u002F end: false matches \u002Fsettings AND any \u002Fsettings\u002F* child route\n  const active = useMatch({ path: '\u002Fsettings', end: false });\n  return (\n    \u003Ca href=\"\u002Fsettings\" style={{ fontWeight: active ? '700' : '400' }}>\n      Settings\n    \u003C\u002Fa>\n  );\n}\n",[19,976,977,986,991,1017,1024,1062,1067,1077,1082],{"__ignoreMap":92},[96,978,979,981,984],{"class":98,"line":99},[96,980,103],{"class":102},[96,982,983],{"class":106}," SettingsLink",[96,985,111],{"class":110},[96,987,988],{"class":98,"line":114},[96,989,990],{"class":188},"  \u002F\u002F end: false matches \u002Fsettings AND any \u002Fsettings\u002F* child route\n",[96,992,993,995,998,1000,1003,1006,1009,1012,1015],{"class":98,"line":133},[96,994,117],{"class":102},[96,996,997],{"class":120}," active",[96,999,124],{"class":102},[96,1001,1002],{"class":106}," useMatch",[96,1004,1005],{"class":110},"({ path: ",[96,1007,1008],{"class":200},"'\u002Fsettings'",[96,1010,1011],{"class":110},", end: ",[96,1013,1014],{"class":120},"false",[96,1016,210],{"class":110},[96,1018,1019,1021],{"class":98,"line":140},[96,1020,227],{"class":102},[96,1022,1023],{"class":110}," (\n",[96,1025,1026,1029,1032,1035,1037,1040,1043,1045,1048,1050,1053,1056,1059],{"class":98,"line":162},[96,1027,1028],{"class":110},"    \u003C",[96,1030,1031],{"class":233},"a",[96,1033,1034],{"class":106}," href",[96,1036,240],{"class":102},[96,1038,1039],{"class":200},"\"\u002Fsettings\"",[96,1041,1042],{"class":106}," style",[96,1044,240],{"class":102},[96,1046,1047],{"class":110},"{{ fontWeight: active ",[96,1049,395],{"class":102},[96,1051,1052],{"class":200}," '700'",[96,1054,1055],{"class":102}," :",[96,1057,1058],{"class":200}," '400'",[96,1060,1061],{"class":110}," }}>\n",[96,1063,1064],{"class":98,"line":173},[96,1065,1066],{"class":110},"      Settings\n",[96,1068,1069,1072,1074],{"class":98,"line":185},[96,1070,1071],{"class":110},"    \u003C\u002F",[96,1073,1031],{"class":233},[96,1075,1076],{"class":110},">\n",[96,1078,1079],{"class":98,"line":192},[96,1080,1081],{"class":110},"  );\n",[96,1083,1084],{"class":98,"line":213},[96,1085,254],{"class":110},[15,1087,1088,1089,1092,1093,1095,1096,1098,1099,1102,1103,1106,1107,1109],{},"The ",[19,1090,1091],{},"end"," option mirrors how ",[19,1094,971],{},"'s ",[19,1097,1091],{}," prop works: ",[19,1100,1101],{},"end: true"," (default) requires an exact match; ",[19,1104,1105],{},"end: false"," matches any path that starts with the pattern. Use ",[19,1108,1105],{}," for parent nav items that have child routes.",[15,1111,1112,1114,1115,1117,1118,1121,1122,1125,1126,1129],{},[63,1113,54],{}," (added in v6.4) intercepts navigations before they happen. It takes a predicate function and returns a blocker object. When the predicate returns ",[19,1116,207],{},", the blocker enters ",[19,1119,1120],{},"state: 'blocked'"," and you must call ",[19,1123,1124],{},"blocker.proceed()"," or ",[19,1127,1128],{},"blocker.reset()"," to resolve it:",[87,1131,1133],{"className":89,"code":1132,"language":91,"meta":92,"style":92},"function EditForm({ isDirty }) {\n  const blocker = useBlocker(\n    ({ currentLocation, nextLocation }) =>\n      isDirty && currentLocation.pathname !== nextLocation.pathname\n  );\n\n  return (\n    \u003C>\n      \u003Cform>...\u003C\u002Fform>\n      {blocker.state === 'blocked' && (\n        \u003Cdialog open>\n          \u003Cp>Unsaved changes — leave anyway?\u003C\u002Fp>\n          \u003Cbutton onClick={blocker.proceed}>Leave\u003C\u002Fbutton>\n          \u003Cbutton onClick={blocker.reset}>Stay\u003C\u002Fbutton>\n        \u003C\u002Fdialog>\n      )}\n    \u003C\u002F>\n  );\n}\n",[19,1134,1135,1151,1165,1184,1201,1205,1209,1215,1220,1234,1250,1263,1277,1294,1311,1320,1325,1330,1335],{"__ignoreMap":92},[96,1136,1137,1139,1142,1145,1148],{"class":98,"line":99},[96,1138,103],{"class":102},[96,1140,1141],{"class":106}," EditForm",[96,1143,1144],{"class":110},"({ ",[96,1146,1147],{"class":155},"isDirty",[96,1149,1150],{"class":110}," }) {\n",[96,1152,1153,1155,1158,1160,1163],{"class":98,"line":114},[96,1154,117],{"class":102},[96,1156,1157],{"class":120}," blocker",[96,1159,124],{"class":102},[96,1161,1162],{"class":106}," useBlocker",[96,1164,782],{"class":110},[96,1166,1167,1170,1173,1175,1178,1181],{"class":98,"line":133},[96,1168,1169],{"class":110},"    ({ ",[96,1171,1172],{"class":155},"currentLocation",[96,1174,22],{"class":110},[96,1176,1177],{"class":155},"nextLocation",[96,1179,1180],{"class":110}," }) ",[96,1182,1183],{"class":102},"=>\n",[96,1185,1186,1189,1192,1195,1198],{"class":98,"line":140},[96,1187,1188],{"class":110},"      isDirty ",[96,1190,1191],{"class":102},"&&",[96,1193,1194],{"class":110}," currentLocation.pathname ",[96,1196,1197],{"class":102},"!==",[96,1199,1200],{"class":110}," nextLocation.pathname\n",[96,1202,1203],{"class":98,"line":162},[96,1204,1081],{"class":110},[96,1206,1207],{"class":98,"line":173},[96,1208,137],{"emptyLinePlaceholder":136},[96,1210,1211,1213],{"class":98,"line":185},[96,1212,227],{"class":102},[96,1214,1023],{"class":110},[96,1216,1217],{"class":98,"line":192},[96,1218,1219],{"class":110},"    \u003C>\n",[96,1221,1222,1225,1227,1230,1232],{"class":98,"line":213},[96,1223,1224],{"class":110},"      \u003C",[96,1226,234],{"class":233},[96,1228,1229],{"class":110},">...\u003C\u002F",[96,1231,234],{"class":233},[96,1233,1076],{"class":110},[96,1235,1236,1239,1242,1245,1248],{"class":98,"line":219},[96,1237,1238],{"class":110},"      {blocker.state ",[96,1240,1241],{"class":102},"===",[96,1243,1244],{"class":200}," 'blocked'",[96,1246,1247],{"class":102}," &&",[96,1249,1023],{"class":110},[96,1251,1252,1255,1258,1261],{"class":98,"line":224},[96,1253,1254],{"class":110},"        \u003C",[96,1256,1257],{"class":233},"dialog",[96,1259,1260],{"class":106}," open",[96,1262,1076],{"class":110},[96,1264,1265,1268,1270,1273,1275],{"class":98,"line":251},[96,1266,1267],{"class":110},"          \u003C",[96,1269,15],{"class":233},[96,1271,1272],{"class":110},">Unsaved changes — leave anyway?\u003C\u002F",[96,1274,15],{"class":233},[96,1276,1076],{"class":110},[96,1278,1279,1281,1283,1285,1287,1290,1292],{"class":98,"line":879},[96,1280,1267],{"class":110},[96,1282,525],{"class":233},[96,1284,528],{"class":106},[96,1286,240],{"class":102},[96,1288,1289],{"class":110},"{blocker.proceed}>Leave\u003C\u002F",[96,1291,525],{"class":233},[96,1293,1076],{"class":110},[96,1295,1296,1298,1300,1302,1304,1307,1309],{"class":98,"line":885},[96,1297,1267],{"class":110},[96,1299,525],{"class":233},[96,1301,528],{"class":106},[96,1303,240],{"class":102},[96,1305,1306],{"class":110},"{blocker.reset}>Stay\u003C\u002F",[96,1308,525],{"class":233},[96,1310,1076],{"class":110},[96,1312,1313,1316,1318],{"class":98,"line":890},[96,1314,1315],{"class":110},"        \u003C\u002F",[96,1317,1257],{"class":233},[96,1319,1076],{"class":110},[96,1321,1322],{"class":98,"line":895},[96,1323,1324],{"class":110},"      )}\n",[96,1326,1327],{"class":98,"line":926},[96,1328,1329],{"class":110},"    \u003C\u002F>\n",[96,1331,1333],{"class":98,"line":1332},18,[96,1334,1081],{"class":110},[96,1336,1338],{"class":98,"line":1337},19,[96,1339,254],{"class":110},[15,1341,1342,1343,1346,1347,1349,1350,1353],{},"Never leave a blocker in ",[19,1344,1345],{},"'blocked'"," state without resolving it — the app will be stuck unable to navigate. Note that ",[19,1348,54],{}," only intercepts React Router navigations; a user typing a new URL directly or pressing the browser's native Back button before React hydrates can still bypass it. For critical guard flows, also attach a ",[19,1351,1352],{},"beforeunload"," event listener.",[10,1355,1357],{"id":1356},"common-interview-questions-at-a-glance","Common Interview Questions at a Glance",[1359,1360,1361,1374,1383,1396,1414,1423,1439,1452],"ul",{},[1362,1363,1364,1370,1371,1373],"li",{},[63,1365,1366,1367,1369],{},"What does ",[19,1368,264],{}," do?"," Moves back one history entry via React Router — prefer it over ",[19,1372,272],{}," because it respects blockers and transition listeners.",[1362,1375,1376,1379,1380,305],{},[63,1377,1378],{},"How do you prevent losing query params when updating one param?"," Use the callback form: ",[19,1381,1382],{},"setSearchParams(prev => { const n = new URLSearchParams(prev); n.set('key', val); return n; })",[1362,1384,1385,1392,1393,305],{},[63,1386,1387,1388,1391],{},"When does ",[19,1389,1390],{},"location.state"," disappear?"," On a hard page refresh (F5), because the History API entry is cleared. Always provide a fallback when reading ",[19,1394,1395],{},"state?.field",[1362,1397,1398,81,1405,1407,1408,1410,1411,1413],{},[63,1399,1400,1401,40,1403,395],{},"What is the difference between ",[19,1402,51],{},[19,1404,28],{},[19,1406,28],{}," was the v5 API. In v6, ",[19,1409,51],{}," replaces it with a cleaner interface; there is no ",[19,1412,28],{}," in React Router v6.",[1362,1415,1416,1422],{},[63,1417,1418,1419,1421],{},"Why can't you call ",[19,1420,297],{}," during render?"," It triggers a state update while React is already rendering, causing an infinite re-render loop and a React invariant warning.",[1362,1424,1425,1428,1429,1431,1432,1434,1435,1125,1437,305],{},[63,1426,1427],{},"How do you implement an unsaved-changes guard?"," Use ",[19,1430,54],{}," with a predicate that returns ",[19,1433,207],{}," when the form is dirty; render a confirmation dialog and call ",[19,1436,1124],{},[19,1438,1128],{},[1362,1440,1441,1451],{},[63,1442,1443,1444,1447,1448,395],{},"When would you use ",[19,1445,1446],{},"useRoutes"," over JSX ",[19,1449,1450],{},"\u003CRoutes>"," When the route tree is dynamic — generated at runtime from an API, a permissions matrix, or a CMS — so you cannot write it as static JSX.",[1362,1453,1454,1461,1462,1465],{},[63,1455,1456,1457,1460],{},"What is ",[19,1458,1459],{},"useHref"," for?"," It resolves a path to a full href string that accounts for the router's ",[19,1463,1464],{},"basename",", making it safe to use in clipboard operations, meta tags, or non-anchor elements without hardcoding path prefixes.",[1467,1468,1469],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":92,"searchDepth":114,"depth":114,"links":1471},[1472,1473,1474,1475,1476,1477],{"id":12,"depth":114,"text":13},{"id":58,"depth":114,"text":59},{"id":308,"depth":114,"text":309},{"id":562,"depth":114,"text":563},{"id":958,"depth":114,"text":959},{"id":1356,"depth":114,"text":1357},"Master React Router v6 navigation hooks for interviews — useNavigate, useParams, useLocation, useSearchParams, useMatch, and useBlocker with real examples.","medium","md","React","react",{},"\u002Fblog\u002Freact-navigation-hooks-guide","\u002Freact\u002Frouting\u002Fnavigation-hooks",{"title":5,"description":1478},"blog\u002Freact-navigation-hooks-guide","Navigation Hooks","Routing","routing","2026-06-24","QEf60iJCKu2zmi6M-fOHVUVwsOvOLXkyvhvykSJ8jC4",1782244083221]