[{"data":1,"prerenderedAt":1229},["ShallowReactive",2],{"content:\u002Fframework-performance\u002Freact-rendering-performance\u002Fusetransition-and-usedeferredvalue-for-inp":3,"surroundings:\u002Fframework-performance\u002Freact-rendering-performance\u002Fusetransition-and-usedeferredvalue-for-inp":1220},{"id":4,"title":5,"body":6,"description":1199,"extension":1200,"meta":1201,"navigation":1213,"path":1214,"seo":1215,"stem":1218,"__hash__":1219},"content\u002Fframework-performance\u002Freact-rendering-performance\u002Fusetransition-and-usedeferredvalue-for-inp\u002Findex.md","useTransition and useDeferredValue for INP",{"type":7,"value":8,"toc":1181},"minimark",[9,14,29,41,202,207,240,244,250,256,262,268,272,277,493,497,744,748,751,755,758,868,872,875,879,882,886,889,959,963,966,970,996,1000,1006,1012,1021,1027,1031,1048,1057,1066,1075,1084,1093,1108,1117,1126,1139,1143,1166,1171,1174,1177],[10,11,13],"h1",{"id":12},"using-usetransition-and-usedeferredvalue-to-improve-inp","Using useTransition and useDeferredValue to Improve INP",[15,16,17,18,23,24,28],"p",{},"This guide is part of ",[19,20,22],"a",{"href":21},"\u002Fframework-performance\u002Freact-rendering-performance\u002F","React Rendering Performance",", within ",[19,25,27],{"href":26},"\u002Fframework-performance\u002F","Framework Performance",". Some updates must feel instant: the character you typed appearing in the input, the checkbox toggling, the tab highlighting. Others can take a moment: the filtered list of 2,000 results, the newly selected tab's heavy content, a chart redrawing. In React's default synchronous rendering, both kinds of work happen together, and the slow part blocks the fast part — the input lags because the list is rendering.",[15,30,31,32,36,37,40],{},"React's concurrent features separate them. ",[33,34,35],"code",{},"useTransition"," marks state updates as non-urgent: React renders them in the background, yielding to the browser so it can paint and handle input, and abandons a stale render if newer input arrives. ",[33,38,39],{},"useDeferredValue"," gives a lagging copy of a value: components using the deferred copy re-render at lower priority, while those using the current value update immediately. For INP, this means the interaction's next paint shows the urgent update quickly, even when the full update takes longer.",[15,42,43],{},[44,45,51,52,51,59,51,63,51,66,51,75,51,81,51,92,51,97,51,105,51,112,51,117,51,121,51,125,51,130,51,136,51,140,51,143,51,149,51,153,51,158,51,164,51,168,51,172,51,176,51,180,51,184,51,188,51,192,51,196,51],"svg",{"viewBox":46,"width":47,"role":48,"ariaLabel":49,"style":50},"0 0 760 200","100%","img","Timeline comparing a filter click that renders a large list synchronously with one that updates the button immediately and renders the list in a transition.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[53,54],"rect",{"className":55,"x":57,"y":57,"width":47,"height":47,"fill":58},[56],"svg-canvas","0","#ffffff",[60,61,62],"title",{},"Filter click with and without a transition",[64,65,49],"desc",{},[53,67],{"x":68,"y":68,"width":69,"height":70,"rx":71,"fill":72,"stroke":73,"style":74},"1","758","198","10","none","currentColor","stroke-opacity:0.18",[76,77,62],"text",{"x":78,"y":79,"fill":73,"style":80},"28.0","34.0","font-size:16px;font-weight:700",[82,83],"line",{"x1":84,"y1":85,"x2":84,"y2":86,"stroke":87,"strokeWidth":88,"strokeDashArray":89,"style":91},"187.0","72.0","156.0","#b8860b","1.5",[90,90],"4","stroke-opacity:0.9",[76,93,96],{"x":78,"y":94,"fill":73,"style":95},"96.0","font-size:12.5px;font-weight:700","Synchronous",[53,98],{"x":99,"y":100,"width":101,"height":102,"rx":103,"fill":72,"stroke":73,"style":104},"119.4","78.0","484.4","26.0","3","stroke-opacity:0.35",[76,106,111],{"x":107,"y":108,"fill":73,"style":109,"textAnchor":110},"361.6","95.5","font-size:11.5px","middle","render button + 2,000 rows",[53,113],{"x":114,"y":100,"width":115,"height":102,"rx":103,"fill":73,"stroke":73,"style":116},"605.3","36.5","fill-opacity:0.06;stroke-opacity:0.4",[76,118,120],{"x":119,"y":108,"fill":73,"style":109,"textAnchor":110},"623.5","paint",[76,122,124],{"x":78,"y":123,"fill":73,"style":95},"134.0","Transition",[53,126],{"x":99,"y":127,"width":115,"height":102,"rx":103,"fill":128,"stroke":87,"style":129},"116.0","#ffc300","fill-opacity:0.24;stroke-opacity:0.9",[76,131,135],{"x":132,"y":133,"fill":73,"style":134,"textAnchor":110},"137.7","133.5","font-size:10.5px","button",[53,137],{"x":138,"y":127,"width":139,"height":102,"rx":103,"fill":128,"stroke":87,"style":129},"157.4","28.9",[76,141,120],{"x":142,"y":133,"fill":73,"style":134,"textAnchor":110},"171.8",[53,144],{"x":145,"y":127,"width":146,"height":102,"rx":103,"fill":147,"stroke":147,"style":148},"187.8","446.4","#0466c8","fill-opacity:0.14;stroke-opacity:0.9",[76,150,152],{"x":151,"y":133,"fill":73,"style":109,"textAnchor":110},"411.0","list in background (yields)",[82,154],{"x1":155,"y1":86,"x2":156,"y2":86,"stroke":73,"style":157},"118.7","726.0","stroke-opacity:0.4",[76,159,163],{"x":160,"y":161,"fill":162,"style":109,"textAnchor":110},"129.4","173.0","#51617a","0ms",[76,165,167],{"x":166,"y":161,"fill":162,"style":109,"textAnchor":110},"194.6","50ms",[76,169,171],{"x":170,"y":161,"fill":162,"style":109,"textAnchor":110},"270.5","100ms",[76,173,175],{"x":174,"y":161,"fill":162,"style":109,"textAnchor":110},"346.4","150ms",[76,177,179],{"x":178,"y":161,"fill":162,"style":109,"textAnchor":110},"422.3","200ms",[76,181,183],{"x":182,"y":161,"fill":162,"style":109,"textAnchor":110},"498.3","250ms",[76,185,187],{"x":186,"y":161,"fill":162,"style":109,"textAnchor":110},"574.2","300ms",[76,189,191],{"x":190,"y":161,"fill":162,"style":109,"textAnchor":110},"650.1","350ms",[76,193,195],{"x":194,"y":161,"fill":162,"style":109,"textAnchor":110},"715.3","400ms",[76,197,201],{"x":84,"y":198,"fill":199,"style":200,"textAnchor":110},"68.0","#8a6608","font-size:12px;font-weight:700","next paint",[203,204,206],"h2",{"id":205},"rapid-diagnosis","Rapid Diagnosis",[208,209,210,218,224,230],"ul",{},[211,212,213,217],"li",{},[214,215,216],"strong",{},"Find interactions with high INP"," where the handler sets state that drives heavy rendering.",[211,219,220,223],{},[214,221,222],{},"Profile the interaction",": a long commit dominated by a large subtree (lists, charts, tab content).",[211,225,226,229],{},[214,227,228],{},"Check whether the urgent feedback is part of the same update"," (input value, selected state).",[211,231,232,235,236,239],{},[214,233,234],{},"Check React version",": concurrent features require React 18 or later with ",[33,237,238],{},"createRoot",".",[203,241,243],{"id":242},"root-cause-analysis","Root Cause Analysis",[15,245,246,249],{},[214,247,248],{},"1. One update for urgent and non-urgent UI."," Input value and results update together.",[15,251,252,255],{},[214,253,254],{},"2. Large subtrees on each interaction."," Lists and charts re-render synchronously.",[15,257,258,261],{},[214,259,260],{},"3. No yielding."," Synchronous renders block the main thread until complete.",[15,263,264,267],{},[214,265,266],{},"4. Stale work."," Fast typing triggers renders for intermediate values that are immediately outdated.",[203,269,271],{"id":270},"step-by-step-resolution","Step-by-Step Resolution",[273,274,276],"h3",{"id":275},"_1-wrap-non-urgent-updates-in-starttransition","1. Wrap non-urgent updates in startTransition",[278,279,284],"pre",{"className":280,"code":281,"language":282,"meta":283,"style":283},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","function Filters({ onChange }) {\n  const [active, setActive] = useState('all');\n  const [isPending, startTransition] = useTransition();\n  function select(value) {\n    setActive(value);                                  \u002F\u002F urgent: button state\n    startTransition(() => onChange(value));            \u002F\u002F non-urgent: heavy list update\n  }\n  return \u003CFilterButtons active={active} onSelect={select} pending={isPending} \u002F>;\n}\n\u002F\u002F trade-off: the list shows old results briefly; show isPending (dimmed list or\n\u002F\u002F spinner) so users know the update is in progress.\n","javascript","",[33,285,286,309,347,372,389,402,423,429,475,481,487],{"__ignoreMap":283},[287,288,290,294,298,302,306],"span",{"class":82,"line":289},1,[287,291,293],{"class":292},"sPARh","function",[287,295,297],{"class":296},"smZ65"," Filters",[287,299,301],{"class":300},"saISM","({ ",[287,303,305],{"class":304},"sQw3B","onChange",[287,307,308],{"class":300}," }) {\n",[287,310,312,315,318,322,325,328,331,334,337,340,344],{"class":82,"line":311},2,[287,313,314],{"class":292},"  const",[287,316,317],{"class":300}," [",[287,319,321],{"class":320},"sPXB4","active",[287,323,324],{"class":300},", ",[287,326,327],{"class":320},"setActive",[287,329,330],{"class":300},"] ",[287,332,333],{"class":292},"=",[287,335,336],{"class":296}," useState",[287,338,339],{"class":300},"(",[287,341,343],{"class":342},"sZ8jY","'all'",[287,345,346],{"class":300},");\n",[287,348,350,352,354,357,359,362,364,366,369],{"class":82,"line":349},3,[287,351,314],{"class":292},[287,353,317],{"class":300},[287,355,356],{"class":320},"isPending",[287,358,324],{"class":300},[287,360,361],{"class":320},"startTransition",[287,363,330],{"class":300},[287,365,333],{"class":292},[287,367,368],{"class":296}," useTransition",[287,370,371],{"class":300},"();\n",[287,373,375,378,381,383,386],{"class":82,"line":374},4,[287,376,377],{"class":292},"  function",[287,379,380],{"class":296}," select",[287,382,339],{"class":300},[287,384,385],{"class":304},"value",[287,387,388],{"class":300},") {\n",[287,390,392,395,398],{"class":82,"line":391},5,[287,393,394],{"class":296},"    setActive",[287,396,397],{"class":300},"(value);                                  ",[287,399,401],{"class":400},"sjfSM","\u002F\u002F urgent: button state\n",[287,403,405,408,411,414,417,420],{"class":82,"line":404},6,[287,406,407],{"class":296},"    startTransition",[287,409,410],{"class":300},"(() ",[287,412,413],{"class":292},"=>",[287,415,416],{"class":296}," onChange",[287,418,419],{"class":300},"(value));            ",[287,421,422],{"class":400},"\u002F\u002F non-urgent: heavy list update\n",[287,424,426],{"class":82,"line":425},7,[287,427,428],{"class":300},"  }\n",[287,430,432,435,438,442,445,448,450,453,456,458,461,463,466,468,470,472],{"class":82,"line":431},8,[287,433,434],{"class":292},"  return",[287,436,437],{"class":300}," \u003C",[287,439,441],{"class":440},"sZBmE","FilterButtons",[287,443,444],{"class":320}," active",[287,446,447],{"class":292},"={",[287,449,321],{"class":300},[287,451,452],{"class":292},"}",[287,454,455],{"class":320}," onSelect",[287,457,447],{"class":292},[287,459,460],{"class":300},"select",[287,462,452],{"class":292},[287,464,465],{"class":320}," pending",[287,467,447],{"class":292},[287,469,356],{"class":300},[287,471,452],{"class":292},[287,473,474],{"class":300}," \u002F>;\n",[287,476,478],{"class":82,"line":477},9,[287,479,480],{"class":300},"}\n",[287,482,484],{"class":82,"line":483},10,[287,485,486],{"class":400},"\u002F\u002F trade-off: the list shows old results briefly; show isPending (dimmed list or\n",[287,488,490],{"class":82,"line":489},11,[287,491,492],{"class":400},"\u002F\u002F spinner) so users know the update is in progress.\n",[273,494,496],{"id":495},"_2-defer-values-passed-to-expensive-children","2. Defer values passed to expensive children",[278,498,500],{"className":280,"code":499,"language":282,"meta":283,"style":283},"function SearchPage({ items }) {\n  const [query, setQuery] = useState('');\n  const deferredQuery = useDeferredValue(query);\n  const isStale = query !== deferredQuery;\n  return (\u003C>\n    \u003Cinput value={query} onChange={(e) => setQuery(e.target.value)} \u002F>\n    \u003Cdiv style={{ opacity: isStale ? 0.6 : 1 }}>\u003CResults items={items} query={deferredQuery} \u002F>\u003C\u002Fdiv>\n  \u003C\u002F>);\n}\nconst Results = React.memo(function Results({ items, query }) { \u002F* heavy filtering + rendering *\u002F });\n\u002F\u002F trade-off: Results must be memoized, or it re-renders with the urgent update too.\n",[33,501,502,516,543,559,577,584,626,691,696,700,739],{"__ignoreMap":283},[287,503,504,506,509,511,514],{"class":82,"line":289},[287,505,293],{"class":292},[287,507,508],{"class":296}," SearchPage",[287,510,301],{"class":300},[287,512,513],{"class":304},"items",[287,515,308],{"class":300},[287,517,518,520,522,525,527,530,532,534,536,538,541],{"class":82,"line":311},[287,519,314],{"class":292},[287,521,317],{"class":300},[287,523,524],{"class":320},"query",[287,526,324],{"class":300},[287,528,529],{"class":320},"setQuery",[287,531,330],{"class":300},[287,533,333],{"class":292},[287,535,336],{"class":296},[287,537,339],{"class":300},[287,539,540],{"class":342},"''",[287,542,346],{"class":300},[287,544,545,547,550,553,556],{"class":82,"line":349},[287,546,314],{"class":292},[287,548,549],{"class":320}," deferredQuery",[287,551,552],{"class":292}," =",[287,554,555],{"class":296}," useDeferredValue",[287,557,558],{"class":300},"(query);\n",[287,560,561,563,566,568,571,574],{"class":82,"line":374},[287,562,314],{"class":292},[287,564,565],{"class":320}," isStale",[287,567,552],{"class":292},[287,569,570],{"class":300}," query ",[287,572,573],{"class":292},"!==",[287,575,576],{"class":300}," deferredQuery;\n",[287,578,579,581],{"class":82,"line":391},[287,580,434],{"class":292},[287,582,583],{"class":300}," (\u003C>\n",[287,585,586,589,592,595,597,599,601,603,605,607,610,613,615,618,621,623],{"class":82,"line":404},[287,587,588],{"class":300},"    \u003C",[287,590,591],{"class":440},"input",[287,593,594],{"class":320}," value",[287,596,447],{"class":292},[287,598,524],{"class":300},[287,600,452],{"class":292},[287,602,416],{"class":320},[287,604,447],{"class":292},[287,606,339],{"class":300},[287,608,609],{"class":304},"e",[287,611,612],{"class":300},") ",[287,614,413],{"class":292},[287,616,617],{"class":296}," setQuery",[287,619,620],{"class":300},"(e.target.value)",[287,622,452],{"class":292},[287,624,625],{"class":300}," \u002F>\n",[287,627,628,630,633,636,638,641,644,647,650,653,656,658,661,664,667,669,671,673,676,678,681,683,686,688],{"class":82,"line":425},[287,629,588],{"class":300},[287,631,632],{"class":440},"div",[287,634,635],{"class":320}," style",[287,637,447],{"class":292},[287,639,640],{"class":300},"{ opacity: isStale ",[287,642,643],{"class":292},"?",[287,645,646],{"class":320}," 0.6",[287,648,649],{"class":292}," :",[287,651,652],{"class":320}," 1",[287,654,655],{"class":300}," }",[287,657,452],{"class":292},[287,659,660],{"class":300},">\u003C",[287,662,663],{"class":440},"Results",[287,665,666],{"class":320}," items",[287,668,447],{"class":292},[287,670,513],{"class":300},[287,672,452],{"class":292},[287,674,675],{"class":320}," query",[287,677,447],{"class":292},[287,679,680],{"class":300},"deferredQuery",[287,682,452],{"class":292},[287,684,685],{"class":300}," \u002F>\u003C\u002F",[287,687,632],{"class":440},[287,689,690],{"class":300},">\n",[287,692,693],{"class":82,"line":431},[287,694,695],{"class":300},"  \u003C\u002F>);\n",[287,697,698],{"class":82,"line":477},[287,699,480],{"class":300},[287,701,702,705,708,710,713,716,718,720,722,724,726,728,730,733,736],{"class":82,"line":483},[287,703,704],{"class":292},"const",[287,706,707],{"class":320}," Results",[287,709,552],{"class":292},[287,711,712],{"class":300}," React.",[287,714,715],{"class":296},"memo",[287,717,339],{"class":300},[287,719,293],{"class":292},[287,721,707],{"class":296},[287,723,301],{"class":300},[287,725,513],{"class":304},[287,727,324],{"class":300},[287,729,524],{"class":304},[287,731,732],{"class":300}," }) { ",[287,734,735],{"class":400},"\u002F* heavy filtering + rendering *\u002F",[287,737,738],{"class":300}," });\n",[287,740,741],{"class":82,"line":489},[287,742,743],{"class":400},"\u002F\u002F trade-off: Results must be memoized, or it re-renders with the urgent update too.\n",[273,745,747],{"id":746},"_3-use-transitions-for-tab-and-route-changes","3. Use transitions for tab and route changes",[15,749,750],{},"Wrap tab switches and navigation state changes in transitions so the old content stays interactive while the new content renders.",[273,752,754],{"id":753},"_4-make-the-heavy-render-cheaper-too","4. Make the heavy render cheaper too",[15,756,757],{},"Transitions defer work; combine them with memoization, virtualization and moving expensive computation out of render.",[15,759,760],{},[44,761,51,764,51,767,51,770,51,772,51,775,51,777,51,782,51,788,51,792,51,795,51,798,51,801,51,804,51,808,51,810,51,814,51,816,51,819,51,821,51,825,51,827,51,830,51,832,51,835,51,838,51,842,51,844,51,846,51,848,51,851,51,854,51,858,51,860,51,863,51,865,51],{"viewBox":762,"width":47,"role":48,"ariaLabel":763,"style":50},"0 0 760 228","Comparison of the two React concurrent features for keeping interactions responsive.",[53,765],{"className":766,"x":57,"y":57,"width":47,"height":47,"fill":58},[56],[60,768,769],{},"useTransition vs useDeferredValue",[64,771,763],{},[53,773],{"x":68,"y":68,"width":69,"height":774,"rx":71,"fill":72,"stroke":73,"style":74},"226",[76,776,769],{"x":78,"y":79,"fill":73,"style":80},[53,778],{"x":78,"y":779,"width":780,"height":781,"rx":57,"fill":73,"stroke":73,"style":116},"56.0","150.4","30.0",[76,783,787],{"x":784,"y":785,"fill":73,"style":95,"textAnchor":786},"38.0","75.5","start","Aspect",[53,789],{"x":790,"y":779,"width":791,"height":781,"rx":57,"fill":73,"stroke":73,"style":116},"178.4","276.8",[76,793,35],{"x":794,"y":785,"fill":73,"style":95,"textAnchor":110},"316.8",[53,796],{"x":797,"y":779,"width":791,"height":781,"rx":57,"fill":73,"stroke":73,"style":116},"455.2",[76,799,39],{"x":800,"y":785,"fill":73,"style":95,"textAnchor":110},"593.6",[53,802],{"x":78,"y":803,"width":780,"height":781,"rx":57,"fill":72,"stroke":73,"style":104},"86.0",[76,805,807],{"x":784,"y":806,"fill":73,"style":95,"textAnchor":786},"105.5","You control",[53,809],{"x":790,"y":803,"width":791,"height":781,"rx":57,"fill":72,"stroke":73,"style":104},[76,811,813],{"x":794,"y":806,"fill":73,"style":812,"textAnchor":110},"font-size:12px","the state update",[53,815],{"x":797,"y":803,"width":791,"height":781,"rx":57,"fill":72,"stroke":73,"style":104},[76,817,818],{"x":800,"y":806,"fill":73,"style":812,"textAnchor":110},"a value passed down",[53,820],{"x":78,"y":127,"width":780,"height":781,"rx":57,"fill":72,"stroke":73,"style":104},[76,822,824],{"x":784,"y":823,"fill":73,"style":95,"textAnchor":786},"135.5","Typical use",[53,826],{"x":790,"y":127,"width":791,"height":781,"rx":57,"fill":72,"stroke":73,"style":104},[76,828,829],{"x":794,"y":823,"fill":73,"style":812,"textAnchor":110},"filters, tabs, navigation",[53,831],{"x":797,"y":127,"width":791,"height":781,"rx":57,"fill":72,"stroke":73,"style":104},[76,833,834],{"x":800,"y":823,"fill":73,"style":812,"textAnchor":110},"search input to results",[53,836],{"x":78,"y":837,"width":780,"height":781,"rx":57,"fill":72,"stroke":73,"style":104},"146.0",[76,839,841],{"x":784,"y":840,"fill":73,"style":95,"textAnchor":786},"165.5","Pending indicator",[53,843],{"x":790,"y":837,"width":791,"height":781,"rx":57,"fill":72,"stroke":73,"style":104},[76,845,356],{"x":794,"y":840,"fill":73,"style":812,"textAnchor":110},[53,847],{"x":797,"y":837,"width":791,"height":781,"rx":57,"fill":72,"stroke":73,"style":104},[76,849,850],{"x":800,"y":840,"fill":73,"style":812,"textAnchor":110},"compare value vs deferred",[53,852],{"x":78,"y":853,"width":780,"height":781,"rx":57,"fill":72,"stroke":73,"style":104},"176.0",[76,855,857],{"x":784,"y":856,"fill":73,"style":95,"textAnchor":786},"195.5","Needs memoized child",[53,859],{"x":790,"y":853,"width":791,"height":781,"rx":57,"fill":73,"stroke":73,"style":116},[76,861,862],{"x":794,"y":856,"fill":73,"style":812,"textAnchor":110},"not always",[53,864],{"x":797,"y":853,"width":791,"height":781,"rx":57,"fill":147,"stroke":147,"style":148},[76,866,867],{"x":800,"y":856,"fill":73,"style":812,"textAnchor":110},"yes",[203,869,871],{"id":870},"verification","Verification",[15,873,874],{},"Record the interaction in the Performance panel with CPU throttling: the first paint after input should occur quickly, followed by background rendering in smaller chunks rather than one long task. The Interactions track should show a short duration for the interaction. In the field, INP for the target should drop.",[203,876,878],{"id":877},"worked-example-a-product-search-page","Worked Example: A Product Search Page",[15,880,881],{},"A retailer's search page filtered 3,000 products client-side as users typed. Each keystroke rendered the input and the full result grid synchronously: 220ms per keystroke on a mid-range phone, with visibly lagging input and INP p75 of 310ms. The team passed a deferred query to a memoized results component, dimmed results while stale, and virtualized the grid. Keystrokes painted in under 30ms; results updated in the background, skipping intermediate queries when users typed quickly. INP p75 fell to 110ms, and search abandonment dropped.",[203,883,885],{"id":884},"how-concurrent-rendering-yields","How Concurrent Rendering Yields",[15,887,888],{},"During a transition, React renders in small units of work and checks whether it should yield to the browser after each. If an urgent update arrives (another keystroke), React pauses or discards the in-progress transition render and handles the urgent update first. Because the main thread is released between units, the browser can paint and respond to input. This is why transitions improve INP: the next paint after an interaction is not blocked by the entire non-urgent render. It also means non-urgent renders may never complete if urgent updates keep arriving — which is fine for intermediate search queries.",[15,890,891],{},[44,892,51,895,51,898,51,901,51,903,51,906,51,908,51,913,51,920,51,926,51,931,51,935,51,940,51,943,51,947,51,952,51,956,51],{"viewBox":893,"width":47,"role":48,"ariaLabel":894,"style":50},"0 0 760 185","Bar chart of INP for typing in a search box with synchronous rendering, a deferred value, and a deferred value plus virtualization.",[53,896],{"className":897,"x":57,"y":57,"width":47,"height":47,"fill":58},[56],[60,899,900],{},"INP p75 for search typing",[64,902,894],{},[53,904],{"x":68,"y":68,"width":69,"height":905,"rx":71,"fill":72,"stroke":73,"style":74},"183",[76,907,900],{"x":78,"y":79,"fill":73,"style":80},[82,909],{"x1":910,"y1":85,"x2":910,"y2":911,"stroke":87,"strokeWidth":88,"strokeDashArray":912,"style":91},"499.7","163.0",[90,90],[76,914,919],{"x":915,"y":916,"fill":73,"style":917,"textAnchor":918},"181.8","92.0","font-size:13px","end","Synchronous rendering",[53,921],{"x":922,"y":100,"width":923,"height":924,"rx":103,"fill":72,"stroke":73,"style":925},"193.8","474.2","19","fill-opacity:0.7;stroke-opacity:0.35",[76,927,930],{"x":928,"y":916,"fill":73,"style":929},"674.0","font-size:12px;font-weight:600","310ms",[76,932,934],{"x":915,"y":933,"fill":73,"style":917,"textAnchor":918},"123.0","useDeferredValue + memo",[53,936],{"x":922,"y":937,"width":938,"height":924,"rx":103,"fill":147,"stroke":147,"style":939},"109.0","229.5","fill-opacity:0.55;stroke-opacity:0.9",[76,941,175],{"x":942,"y":933,"fill":73,"style":929},"429.2",[76,944,946],{"x":915,"y":945,"fill":73,"style":917,"textAnchor":918},"154.0","+ virtualized grid",[53,948],{"x":922,"y":949,"width":950,"height":924,"rx":103,"fill":128,"stroke":87,"style":951},"140.0","168.3","fill-opacity:0.7;stroke-opacity:0.9",[76,953,955],{"x":954,"y":945,"fill":73,"style":929},"368.0","110ms",[76,957,958],{"x":910,"y":198,"fill":199,"style":200,"textAnchor":110},"good",[203,960,962],{"id":961},"choosing-which-updates-are-urgent","Choosing Which Updates Are Urgent",[15,964,965],{},"The decision is a product question as much as a technical one: what must the user see immediately to know their action registered? Usually that is the direct feedback on the control they touched — the character in the input, the pressed state of the button, the checked checkbox, the highlighted tab. Everything derived from it — results, totals, charts, the content of the selected tab — can follow a moment later, as long as there is a pending indicator. Write this down for each key interaction, and structure state so that the urgent part lives in its own state variable, updated outside the transition.",[203,967,969],{"id":968},"common-mistakes","Common Mistakes",[208,971,972,978,984,990],{},[211,973,974,977],{},[214,975,976],{},"Wrapping the input value itself in a transition."," The input lags; keep it urgent.",[211,979,980,983],{},[214,981,982],{},"Deferred value without memoization."," The child re-renders with the urgent value anyway.",[211,985,986,989],{},[214,987,988],{},"No pending indicator."," Users think the click did nothing.",[211,991,992,995],{},[214,993,994],{},"Expecting transitions to speed up blocking code."," Synchronous loops inside render still block.",[203,997,999],{"id":998},"edge-cases","Edge Cases",[15,1001,1002,1005],{},[214,1003,1004],{},"Controlled inputs."," Input state must update synchronously; transitions are for derived updates.",[15,1007,1008,1011],{},[214,1009,1010],{},"Suspense and transitions."," Transitions keep showing old content instead of fallbacks when new content suspends, avoiding jarring loading states.",[15,1013,1014,1017,1018,1020],{},[214,1015,1016],{},"Server Actions."," In frameworks with server actions, ",[33,1019,35],{}," tracks pending state for the action.",[15,1022,1023,1026],{},[214,1024,1025],{},"Older React versions."," Concurrent features need React 18+ and the concurrent root API.",[203,1028,1030],{"id":1029},"faq","FAQ",[1032,1033,1036,1040],"details",{"className":1034},[1035],"faq-item",[1037,1038,1039],"summary",{},"What is the difference between useTransition and useDeferredValue?",[15,1041,1042,1044,1045,1047],{},[33,1043,35],{}," marks a state update as non-urgent where you set it. ",[33,1046,39],{}," creates a lagging copy of a value for components that should update at lower priority.",[1032,1049,1051,1054],{"className":1050},[1035],[1037,1052,1053],{},"Do transitions improve INP?",[15,1055,1056],{},"Yes, when the slow part of an interaction is a large re-render. The urgent update paints quickly, and the expensive render no longer blocks the next paint.",[1032,1058,1060,1063],{"className":1059},[1035],[1037,1061,1062],{},"Can I use transitions for data fetching?",[15,1064,1065],{},"Yes. With Suspense-enabled data sources or server actions, transitions keep the current UI visible while new data loads.",[1032,1067,1069,1072],{"className":1068},[1035],[1037,1070,1071],{},"Why does my input still lag?",[15,1073,1074],{},"The input's own state may be inside the transition, or the expensive child is not memoized and re-renders with the urgent update.",[1032,1076,1078,1081],{"className":1077},[1035],[1037,1079,1080],{},"Is useDeferredValue the same as debouncing?",[15,1082,1083],{},"No. Debouncing waits a fixed time before updating; deferred values render as soon as possible at lower priority and skip stale work automatically.",[1032,1085,1087,1090],{"className":1086},[1035],[1037,1088,1089],{},"Do transitions work on the server?",[15,1091,1092],{},"They are a client-side scheduling feature. On the server, rendering happens once per request.",[1032,1094,1096,1099],{"className":1095},[1035],[1037,1097,1098],{},"How do I show that an update is pending?",[15,1100,1101,1102,1104,1105,1107],{},"Use ",[33,1103,356],{}," from ",[33,1106,35],{},", or compare the current and deferred values, and dim or annotate the content that is still updating.",[1032,1109,1111,1114],{"className":1110},[1035],[1037,1112,1113],{},"Can transitions make total rendering slower?",[15,1115,1116],{},"Slightly, due to yielding overhead, but users perceive the app as faster because urgent feedback is immediate.",[1032,1118,1120,1123],{"className":1119},[1035],[1037,1121,1122],{},"Do transitions help on fast devices?",[15,1124,1125],{},"Less noticeably, because renders finish quickly anyway. Their value shows on mid-range and low-end phones, where INP problems concentrate.",[1032,1127,1129,1132],{"className":1128},[1035],[1037,1130,1131],{},"Can I use transitions with external state stores?",[15,1133,1134,1135,1138],{},"Stores read via ",[33,1136,1137],{},"useSyncExternalStore"," update synchronously, so transitions cannot defer them. Keep the derived, expensive state in React state if you want transitions to apply.",[203,1140,1142],{"id":1141},"related","Related",[208,1144,1145,1152,1159],{},[211,1146,1147,1151],{},[19,1148,1150],{"href":1149},"\u002Fframework-performance\u002Freact-rendering-performance\u002Fstopping-context-re-render-cascades\u002F","Stopping context re-render cascades"," — reduce what renders.",[211,1153,1154,1158],{},[19,1155,1157],{"href":1156},"\u002Fcore-web-vitals-measurement\u002Foptimizing-inp-with-scheduler-yield\u002F","Optimizing INP with scheduler.yield"," — yielding outside React.",[211,1160,1161,1165],{},[19,1162,1164],{"href":1163},"\u002Frendering-css-performance\u002Fdom-size-and-list-virtualization\u002Fvirtualizing-long-lists-in-react\u002F","Virtualizing long lists in React"," — cheaper renders for long lists.",[1167,1168,1170],"script",{"type":1169},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"Using useTransition and useDeferredValue to Improve INP\",\n  \"description\": \"How React's concurrent features keep urgent updates fast and improve INP, with patterns for search, filters, tabs and navigation.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Wrap non-urgent updates in startTransition\",\n      \"text\": \"Wrap non-urgent updates in startTransition\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Defer values passed to expensive children\",\n      \"text\": \"Defer values passed to expensive children\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Use transitions for tab and route changes\",\n      \"text\": \"Wrap tab switches and navigation state changes in transitions so the old content stays interactive while the new content renders.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Make the heavy render cheaper too\",\n      \"text\": \"Transitions defer work; combine them with memoization, virtualization and moving expensive computation out of render.\"\n    }\n  ]\n}\n",[1167,1172,1173],{"type":1169},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"Using useTransition and useDeferredValue to Improve INP\",\n  \"description\": \"How React's concurrent features keep urgent updates fast and improve INP, with patterns for search, filters, tabs and navigation.\",\n  \"datePublished\": \"2026-10-06\",\n  \"dateModified\": \"2026-10-06\",\n  \"author\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"publisher\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"mainEntityOfPage\": {\n    \"@type\": \"WebPage\",\n    \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fframework-performance\u002Freact-rendering-performance\u002Fusetransition-and-usedeferredvalue-for-inp\u002F\"\n  }\n}\n",[1167,1175,1176],{"type":1169},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"name\": \"Home\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 2,\n      \"name\": \"Framework Performance\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fframework-performance\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"React Rendering Performance\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fframework-performance\u002Freact-rendering-performance\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"useTransition and useDeferredValue for INP\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fframework-performance\u002Freact-rendering-performance\u002Fusetransition-and-usedeferredvalue-for-inp\u002F\"\n    }\n  ]\n}\n",[1178,1179,1180],"style",{},"html pre.shiki code .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}html pre.shiki code .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}html pre.shiki code .sZBmE, html code.shiki .sZBmE{--shiki-default:#024C1A;--shiki-dark:#72F088;--shiki-light:#024C1A}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);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}",{"title":283,"searchDepth":311,"depth":311,"links":1182},[1183,1184,1185,1191,1192,1193,1194,1195,1196,1197,1198],{"id":205,"depth":311,"text":206},{"id":242,"depth":311,"text":243},{"id":270,"depth":311,"text":271,"children":1186},[1187,1188,1189,1190],{"id":275,"depth":349,"text":276},{"id":495,"depth":349,"text":496},{"id":746,"depth":349,"text":747},{"id":753,"depth":349,"text":754},{"id":870,"depth":311,"text":871},{"id":877,"depth":311,"text":878},{"id":884,"depth":311,"text":885},{"id":961,"depth":311,"text":962},{"id":968,"depth":311,"text":969},{"id":998,"depth":311,"text":999},{"id":1029,"depth":311,"text":1030},{"id":1141,"depth":311,"text":1142},"How React's concurrent features keep urgent updates fast and improve INP, with patterns for search, filters, tabs and navigation.","md",{"slug":1202,"type":1203,"breadcrumb":1204,"datePublished":1212,"dateModified":1212},"usetransition-and-usedeferredvalue-for-inp","article",[1205,1208,1209,1210],{"name":1206,"url":1207},"Home","\u002F",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":1211},"\u002Fframework-performance\u002Freact-rendering-performance\u002Fusetransition-and-usedeferredvalue-for-inp\u002F","2026-10-06",true,"\u002Fframework-performance\u002Freact-rendering-performance\u002Fusetransition-and-usedeferredvalue-for-inp",{"title":1216,"description":1217},"useTransition and useDeferredValue to Improve INP","Keep inputs responsive while heavy React renders run in the background: mark non-urgent updates with useTransition, defer values, and show pending states.","framework-performance\u002Freact-rendering-performance\u002Fusetransition-and-usedeferredvalue-for-inp\u002Findex","5mk-Y_Cxaawaqr5IdIebUKL3RYsQdju7lPyOElswDFs",[1221,1225],{"title":1222,"path":1223,"stem":1224},"Stopping Context Re-Render Cascades","\u002Fframework-performance\u002Freact-rendering-performance\u002Fstopping-context-re-render-cascades","framework-performance\u002Freact-rendering-performance\u002Fstopping-context-re-render-cascades\u002Findex",{"title":1226,"path":1227,"stem":1228},"When useMemo and useCallback Actually Help","\u002Fframework-performance\u002Freact-rendering-performance\u002Fwhen-usememo-and-usecallback-actually-help","framework-performance\u002Freact-rendering-performance\u002Fwhen-usememo-and-usecallback-actually-help\u002Findex",1791308077431]