Characterization tests, छोटे सुरक्षित कदम और state को अलग करके Claude Code के साथ React कंपोनेंट्स को बिना व्यवहार बदले सुरक्षित रूप से रिफैक्टर करना सीखें।

React रिफैक्टर्स इसलिए जोखिम भरे महसूस होते हैं क्योंकि ज्यादातर कंपोनेंट छोटे, साफ़ ब्लॉक्स नहीं होते। वे UI, state, effects और “बस एक और prop” फिक्स का जीवित ढेर होते हैं। जब आप संरचना बदलते हैं, तो अक्सर बिना इरादे के timing, identity, या data flow बदल जाते हैं।
रिफैक्टर तब सबसे ज्यादा व्यवहार बदलता है जब आप अनजाने में:\n
key बदल गया।\n- effects कब चलते हैं बदल जाते हैं क्योंकि dependencies शिफ्ट हुईं या mounting/unmounting बदला।\n- memoization टूट जाती है, जिससे handlers और derived values हर render पर बदलते हैं।\n- event handling (focus, blur, keyboard, pointer) शिफ्ट हो जाती है, खासकर जब मार्कअप रैप या स्प्लिट किया गया हो।\n- fetching या subscriptions duplicate होने लगती हैं क्योंकि लॉजिक को copy किया गया बजाय centralize करने के।रिफैक्टर्स अक्सर री-राइट में बदल जाते हैं जब “साफ़-सुथरा करना” और “सुधार” मिल जाते हैं। आप एक component निकालकर शुरू करते हैं, फिर बहुत सी चीज़ों का नाम बदल देते हैं, फिर state shape “सुधार” करते हैं, फिर एक hook बदल देते हैं। जल्दी ही आप लॉजिक और layout दोनों बदल रहे होते हैं। बिना गार्डरेल्स के, यह पता लगाना मुश्किल होता है कि किस बदलाव ने बग पैदा किया।
एक सुरक्षित रिफैक्टर का एक सरल वादा होता है: उपयोगकर्ताओं को वही व्यवहार मिलता है, और आपका कोड साफ़ हो जाता है। Props, events, loading states, error states, और edge cases को वैसे ही व्यवहार करना चाहिए। अगर व्यवहार बदलता है, तो वह जानबूझकर, छोटा और स्पष्ट होना चाहिए।
अगर आप Claude Code (या किसी भी coding assistant) के साथ React कंपोनेंट्स रिफैक्टर कर रहे हैं, तो इसे ऑटोपायलट नहीं बल्कि तेज़ pair programmer की तरह ट्रीट करें। उससे कहें कि एडिट करने से पहले जोखिम बताये, छोटे-छोटे कदमों वाली योजना प्रस्तावित करे, और बताए कि उसने व्यवहार कैसे चेक किया कि वह वही बना रहा। फिर खुद वैलिडेट करें: ऐप चलाएँ, अजीब रास्तों पर क्लिक करें, और उन टेस्ट्स पर भरोसा करें जो कंपोनेंट आज क्या करता है उसे कैप्चर करते हैं, न कि वह जो आप चाहते हैं कि वह करे।
एक ऐसा कंपोनेंट चुनें जो आपको वाकई समय खा रहा हो। पूरे पेज को नहीं, न ही “UI layer” को, और न ही अस्पष्ट “साफ़-सुथरा” को। ऐसे एकल कंपोनेंट को चुनें जो पढ़ने में कठिन, बदलने में कठिन, या fragile state और side effects से भरा हो। एक तंग लक्ष्य assistant के सुझावों को सत्यापित करना भी आसान बनाता है।
पाँच मिनट में चेक करने योग्य लक्ष्य लिखें। अच्छे लक्ष्य संरचना के बारे में होते हैं, परिणामों के बारे में नहीं: “छोटे कंपोनेंट्स में विभाजित करें,” “state को समझना आसान बनाएं,” या “किसी आधे ऐप को mock किए बिना टेस्टेबल बनाएं।” “इसे बेहतर बनाओ” या “परफॉर्मेंस सुधारो” जैसे लक्ष्यों से बचें जब तक आपके पास मेट्रिक और ज्ञात bottleneck न हो।
एडिटर खोलने से पहले सीमाएँ तय करें। सबसे सुरक्षित रिफैक्टर्स नीरस होते हैं:
फिर उन्हीं dependencies को सूचीबद्ध करें जो कोड मूव करते समय व्यवहार चुपचाप तोड़ सकती हैं: API कॉल्स, context providers, routing params, feature flags, analytics events, और shared global state।
एक ठोस उदाहरण: आपके पास 600-line OrdersTable है जो data fetch करता है, उसे filter करता है, selection manage करता है, और details के साथ एक drawer दिखाता है। एक स्पष्ट लक्ष्य हो सकता है: “row rendering और drawer UI को components में extract करें, और selection state को एक reducer में ले जाएँ, बिना किसी UI बदलाव के।” यह लक्ष्य बताता है कि “done” क्या दिखेगा और क्या स्कोप से बाहर है।
रिफैक्टर से पहले कंपोनेंट को black box की तरह व्यवहार करें। आपका काम यह कैप्चर करना है कि वह आज क्या करता है, न कि आप चाहें कि वह क्या करे। यह रिफैक्टर को redesign में बदलने से रोकता है।
शुरू करें वर्तमान व्यवहार को साधारण भाषा में लिखकर: इन inputs के साथ UI वह output दिखाता है। props, URL params, feature flags, और कोई भी data जो context या store से आता है, सब शामिल करें। अगर आप Claude Code का उपयोग कर रहे हैं, तो छोटा, फोकस्ड स्निपेट पेस्ट करें और उससे कहें कि वह व्यवहार को सटीक वाक्यों में फिर से बताए जिन्हें आप बाद में चेक कर सकें।
वे UI states कवर करें जिन्हें लोग वास्तव में देखते हैं। एक कंपोनेंट खुश रास्ते पर ठीक लग सकता है जबकि लोडिंग, empty, या error पर टूट सकता है।
साथ ही उन implicit नियमों को कैप्चर करें जिन्हें भूलना आसान है और जो अक्सर रिफैक्टर्स को तोड़ते हैं:
उदाहरण: आपके पास एक user table है जो results लोड करता है, search सपोर्ट करता है, और “Last active” से sort करता है। लिखें कि क्या होता है जब search खाली हो, जब API खाली सूची लौटाता है, जब API error दे, और जब दो उपयोगकर्ताओं की “Last active” समय समान हो। छोटे विवरण नोट करें जैसे sorting case-insensitive है या नहीं, और क्या फिल्टर बदलने पर table current page रखता है।
जब आपके नोट्स बोरिंग और विशिष्ट लगेँ, तो आप तैयार हैं।
Characterization tests वे टेस्ट हैं जो बताते हैं कि "यह आज क्या करता है"। वे वर्तमान व्यवहार का वर्णन करते हैं, भले ही वह अजीब या लंबे समय में गलत हो। यह उल्टा लगता है, पर यह रिफैक्टर को चुपचाप री-राइट बनने से रोकता है।
जब आप Claude Code के साथ React कंपोनेंट्स रिफैक्टर कर रहे हों, तो ये टेस्ट आपकी safety rails हैं। टूल कोड को reshape कर सकता है, पर आप तय करें कि क्या न बदलना है।
उन चीज़ों पर ध्यान दें जिनपर उपयोगकर्ता (और अन्य कोड) निर्भर करते हैं:
टेस्ट्स को स्थिर रखने के लिए, implementation पर नहीं बल्कि outcomes पर assert करें। “Save बटन disabled हो जाता है और एक संदेश दिखता है” को प्राथमिकता दें बजाए “setState कॉल हुआ” या “यह hook चला” जैसे assertions के। अगर कोई टेस्ट इस वजह से टूटता है कि आपने एक component का नाम बदल दिया या hooks reorder कर दिए, तो वह व्यवहार की सुरक्षा नहीं कर रहा।
Async व्यवहार में अक्सर रिफैक्टर्स timing बदल देते हैं। इसे स्पष्ट रूप से ट्रीट करें: UI के settle होने का इंतजार करें, फिर assert करें। अगर timers हैं (debounced search, delayed toasts), तो fake timers इस्तेमाल करके समय आगे बढ़ाएँ। नेटवर्क कॉल्स के लिए fetch mock करें और success और failure के बाद उपयोगकर्ता को जो दिखाई देता है उसे assert करें। Suspense जैसी flows के लिए fallback और resolved view दोनों का टेस्ट करें।
उदाहरण: एक “Users” table “No results” तभी दिखाता है जब search पूरा हो गया हो। एक characterization test को उस sequence को लॉक कर देना चाहिए: पहले loading indicator, फिर या तो rows या empty message, चाहे आप बाद में component कैसे भी स्प्लिट करें।
जीत "बड़े बदलाव तेज़ी से" नहीं है। जीत यह है कि कंपोनेंट क्या करता है इसका स्पष्ट चित्र मिल जाये, फिर एक-एक करके छोटे बदलाव करते हुए व्यवहार स्थिर रखें।
शुरू करें कंपोनेंट पेस्ट करके और उसकी जिम्मेदारियों का plain-English summary माँगकर। specifics के लिए दबाव डालें: वह कौनसा data दिखाता है, कौन से user actions वह संभालता है, और कौन से side effects वह ट्रिगर करता है (fetching, timers, subscriptions, analytics)। इससे अक्सर वे छुपे हुए काम सामने आते हैं जो रिफैक्टर्स को जोखिम भरा बनाते हैं।
फिर, dependency map माँगें। हर input और output की सूची चाहिए: props, context reads, custom hooks, local state, derived values, effects, और कोई module-level helpers। एक उपयोगी मैप यह भी बताए कि क्या सुरक्षित रूप से मूव किया जा सकता है (pure calculations) और क्या “sticky” है (timing, DOM, network)।
फिर उससे extraction candidates प्रस्तावित करने को कहें, एक कड़ाई के साथ: pure view pieces को stateful controller से अलग करें। JSX-heavy सेक्शन्स जो केवल props लेते हैं, वे सबसे अच्छे पहले extraction होते हैं। वे सेक्शन्स जो event handlers, async calls, और state updates mix करते हैं, आमतौर पर नहीं।
एक workflow जो असली कोड में टिकता है:\n
Checkpoints महत्वपूर्ण हैं। Claude Code से कहें कि एक मिनिमल योजना दें जहाँ हर कदम commit और revert किया जा सके। एक व्यावहारिक checkpoint हो सकता है: “Extract <TableHeader> with no logic changes” इससे पहले कि आप sorting state छुएँ।
ठोस उदाहरण: अगर एक component customer table रेंडर करता है, filters नियंत्रित करता है, और data fetch करता है, तो पहले table markup (headers, rows, empty state) को pure component में extract करें। उसके बाद ही filter state या fetch effect को मूव करें। यह क्रम JSX के साथ bugs के फैलने को रोकता है।
जब आप बड़े कंपोनेंट को विभाजित करते हैं, तो जोखिम सिर्फ JSX मूव करने का नहीं होता। जोखिम यह है कि आप अनजाने में data flow, timing, या event wiring बदल दें। extraction को पहले copy-and-wire अभ्यास के रूप में मानें, और बाद में cleanup के रूप में।
शुरू करें UI में पहले से मौजूद सीमाओं को ढूँढ कर, न कि फाइल स्ट्रक्चर में। ऐसे हिस्सों को देखें जिन्हें आप एक वाक्य में अपनी अलग “चीज़” बता सकते हैं: actions वाला header, filter bar, results list, footer with pagination।
एक सुरक्षित पहला कदम pure presentational components निकालना है: props इन, JSX आउट। उन्हें जानबूझकर बोर रखें—कोई नया state नहीं, कोई नया effect नहीं, कोई नया API कॉल नहीं। अगर मूल कंपोनेंट में एक क्लिक हैंडलर था जो तीन काम करता था, तो वह हैंडलर parent में ही रखें और नीचे पास करें।
सुरक्षित boundaries जो आमतौर पर काम करते हैं: header area, list और row item, filters (केवल inputs), footer controls (pagination, totals, bulk actions), और dialogs (open/close और callbacks पास की गयी)।
नामकरण लोगों से ज्यादा मायने रखता है। विशिष्ट नाम चुनें जैसे UsersTableHeader या InvoiceRowActions। “Utils” या “HelperComponent” जैसे generic नामों से बचें क्योंकि वे जिम्मेदारियाँ छिपाते हैं और concerns मिलाने को आमंत्रित करते हैं।
container component तभी introduce करें जब सच्ची ज़रूरत हो: UI का एक हिस्सा जिसे coherent रहने के लिए state या effects को own करना पड़े। तब भी इसे संकीर्ण रखें। एक अच्छा container एक उद्देश्य (जैसे “filter state”) own करे और बाकी सब props के रूप में पास करे।
उलझे हुए कंपोनेंट्स आमतौर पर तीन तरह के डेटा मिलाते हैं: वास्तविक UI state (जो user ने बदला), derived data (जो आप compute कर सकते हैं), और server state (नेटवर्क से आने वाला)। अगर आप इन सबको local state की तरह ट्रीट करते हैं, तो रिफैक्टर्स जोखिम भरे हो जाते हैं क्योंकि आप अनजाने में यह बदल सकते हैं कि चीज़ें कब अपडेट होती हैं।
शुरू करें हर data के टुकड़े को लेबल कर के। पूछें: क्या user इसे एडिट करता है, या क्या मैं इसे props/state/fetched data से compute कर सकता हूँ? और पूछें: क्या यह value यहां owned है, या बस पास होकर जा रही है?
Derived values useState में नहीं होने चाहिए। उन्हें छोटे फ़ंक्शन में या अगर महंगा हो तो memoized selector में रखें। इससे state updates कम होंगे और व्यवहार पढ़ना आसान होगा।
एक सुरक्षित पैटर्न:\n
useState में रखें।\n- view-only values उन inputs से निकालें।\n- computed values नीचे पास करें, न कि setters, जब तक child सचमुच उन्हें edit न करे।\n- अगर प्रदर्शन महत्वपूर्ण है, तो भारी गणनाओं को useMemo में रखें।Effects तब व्यवहार तोड़ते हैं जब वे बहुत कुछ करते हैं या गलत dependencies पर react करते हैं। हर उद्देश्य के लिए एक effect रखें: एक localStorage sync के लिए, एक fetching के लिए, एक subscription के लिए। अगर एक effect कई values पढ़ता है, तो वह अक्सर अतिरिक्त जिम्मेदारियों को छिपा रहा होता है।
अगर आप Claude Code का उपयोग कर रहे हैं, तो एक छोटा बदलाव माँगें: एक effect को दो में बाँट दें, या एक जिम्मेदारी एक helper में मूव करें। फिर हर मूव के बाद characterization tests चलाएँ।
prop drilling से सावधान रहें। इसे context से बदलना तभी मदद करता है जब इससे repeated wiring हटे और ownership स्पष्ट हो। एक अच्छा संकेत तब मिलता है जब context एक app-level concept जैसा लगे (current user, theme, feature flags), न कि एक workaround जो सिर्फ एक component tree के लिए हो।
उदाहरण: एक table component दोनों rows और filteredRows को state में रख सकता है। rows को state रखें, filteredRows को rows और query से compute करें, और filtering को एक pure function में रखें ताकि उसका टेस्ट करना आसान और टूटना मुश्किल हो।
रिफैक्टर्स सबसे अधिक तब गलत होते हैं जब आप बहुत कुछ बदल देते हैं इससे पहले कि आप नोट करें। इसका उपाय सरल है: छोटे checkpoints में काम करें, और हर checkpoint को एक मिनी-रिलीज की तरह ट्रीट करें। भले ही आप एक ही ब्रांच पर काम कर रहे हों, अपने बदलावों को PR-आकार का रखें ताकि आप देख सकें क्या टूटा और क्यों।
हर मायने रखने वाले मूव के बाद (किसी component का extraction, state flow बदलना), रुकें और साबित करें कि आपने व्यवहार नहीं बदला। वह प्रमाण automated (tests) और manual (ब्राउज़र में जल्दी से चेक) दोनों हो सकता है। लक्ष्य परफेक्शन नहीं है—यह तेज़ पता लगाने का है।
एक व्यावहारिक checkpoint लूप:\n
अगर आप Koder.ai जैसी प्लेटफ़ॉर्म का उपयोग करते हैं, तो snapshots और rollback आपके लिए safety rails की तरह काम कर सकते हैं। तब भी सामान्य commits रखें, पर snapshots मदद करते हैं जब आपको एक "known good" संस्करण के खिलाफ तुलना करनी हो या कोई experiment sideways चला जाए।
एक सरल behavior ledger रखें: यह सिर्फ एक छोटा नोट होता है कि आपने क्या verified किया, और यह आपको बार-बार वही चीज़ें चेक करने से बचाता है।
उदाहरण:\n
जब कुछ टूटता है, ledger बताता है कि क्या फिर से चेक करना है, और आपके checkpoints इसे revert करना सस्ता बनाते हैं।
अधिकतर रिफैक्टर्स छोटे, बोरिंग तरीकों से fail होते हैं। UI अभी भी काम कर सकता है, पर spacing नियम गायब हो सकता है, क्लिक हैंडलर दो बार चल सकता है, या सूची टाइप करते समय फोकस खो सकती है। असिस्टेंट्स इससे और खराब कर सकते हैं क्योंकि कोड साफ़ दिखता है भले ही व्यवहार drift कर रहा हो।
एक सामान्य कारण संरचना बदलना है। आप एक component निकालते हैं और चीज़ों को एक अतिरिक्त <div> में रैप कर देते हैं, या <button> की जगह एक clickable <div> रख देते हैं। CSS selectors, layout, keyboard navigation, और test queries बिना किसी को पता चले बदल सकते हैं।
जो जाल सबसे ज्यादा टूटते हैं:
{} या () => {} नई objects/functions बनाती हैं जो extra re-renders और child state reset ट्रिगर कर सकती हैं। उन props पर ध्यान रखें जो पहले stable थे।\n- Hook dependency गलतियाँ: लॉजिक को useEffect, useMemo, या useCallback में मूव करने से stale values या loops आ सकते हैं अगर dependencies गलत हों। अगर एक effect पहले "on click" चलता था, तो उसे ऐसे किसी चीज़ में न बदलें जो "जब कुछ भी बदलता है" पर चले।\n- अनुमति के बिना व्यवहार upgrade करना: edge case fix करना, sorting rules बदलना, या validation सुधारना एक product change है। पहले आज के व्यवहार से मेल करें, भले ही वह अजीब हो।एक ठोस उदाहरण: एक table component को स्प्लिट करते समय row keys को ID से array index पर बदलना ठीक दिख सकता है, पर यह reorder होने पर selection state तोड़ सकता है। "साफ़" होना बोनस है; "समान व्यवहार" ही requirement है।
मर्ज करने से पहले आप proof चाहते हैं कि रिफैक्टर ने व्यवहार नहीं बदला। सबसे आसान संकेत बोरिंग है: सब कुछ अब भी बिना आपके "टेस्ट ठीक करने" के काम करता है।
अंतिम छोटे बदलाव के बाद यह तेज़ पास चलाएँ:
onChange user input पर चले, mount पर न चले)।\n- Focus और keyboard व्यवहार वैसा ही महसूस हो: tab order, Enter और Escape handling, और actions के बाद फोकस कहाँ जाता है।\n- Analytics और साइड इफेक्ट्स एक ही बार और उसी क्षण हों (उदा. एक “Viewed” event per screen load, न कि हर re-render पर)।एक तेज़ sanity check: component खोलें और एक अजीब flow चलाएँ, जैसे error ट्रिगर करें, retry करें, फिर filters clear करें। रिफैक्टर्स अक्सर transitions को तोड़ देते हैं भले ही main path काम कर रहा हो।
अगर कोई आइटम fail करे, तो आखिरी बदलाव revert करें और उसे छोटे कदम में फिर से करें। यह आमतौर पर बड़े diff को debug करने से तेज़ होता है।
मान लीजिए ProductTable कंपोनेंट सब कुछ कर रहा है: data fetch करता है, filters manage करता है, pagination control करता है, delete के लिए confirm dialog खोलता है, और row actions (edit, duplicate, archive) संभालता है। यह छोटा शुरू हुआ था और फिर 900-line फ़ाइल बन गई।
लक्षण परिचित हैं: state useState कॉल्स में बिखरी हुई है, कुछ useEffects एक विशिष्ट क्रम में चलते हैं, और एक “हर्मलेस” बदलाव pagination को तोड़ देता है जब एक filter active हो। लोग इसे छूना बंद कर देते हैं क्योंकि यह अनिश्चित महसूस होता है।
संरचना बदलने से पहले कुछ React characterization tests लॉक करें। उपयोगकर्ता क्या करता है उस पर ध्यान दें, आंतरिक state पर नहीं:\n
अब आप छोटे commits में रिफैक्टर कर सकते हैं। एक साफ़ extraction योजना कुछ इस तरह हो सकती है: FilterBar controls render करे और filter changes emit करे; TableView rows और pagination render करे; RowActions action menu और confirm dialog UI को संभाले; और एक useProductTable hook messy logic (query params, derived state, और side effects) को own करे।
क्रम मायने रखता है। पहले dumb UI निकालें (TableView, FilterBar) और props को बिना बदले पास करें। जोखिम वाला हिस्सा अंतिम रखें: state और effects को useProductTable में मूव करना। जब आप ऐसा करें, पुराने prop names और event shapes रखें ताकि tests पास होते रहें। अगर कोई test फेल हो, तो आपने व्यवहार बदला है, न कि सिर्फ़ style।
अगर आप चाहते हैं कि Claude Code के साथ React रिफैक्टर्स हर बार सुरक्षित महसूस हों, तो आपने जो किया उसे एक छोटा template बनाकर दोहराने योग्य बनाएं। लक्ष्य अधिक प्रक्रिया नहीं है; लक्ष्य कम आश्चर्य है।
किसी भी कंपोनेंट पर पालन करने लायक एक छोटी playbook लिखें, भले ही आप थके हों या जल्दी में हों:\n
इसे अपने नोट्स या रेपो में snippet के रूप में रखें ताकि अगला रिफैक्टर वही safety rails से शुरू हो।
एक बार कंपोनेंट स्थिर और पढ़ने में आसान हो जाए, तो अगला पास user impact के आधार पर चुनें। सामान्य क्रम होता है: accessibility पहले (labels, focus, keyboard), फिर performance (memoization, expensive renders), फिर cleanup (types, naming, dead code)। इन तीनों को एक ही PR में न मिलाएँ।
यदि आप vibe-coding workflow जैसे Koder.ai (koder.ai) का उपयोग करते हैं, तो planning mode आपको कदमों का outline करने में मदद कर सकता है, और snapshots/rollback checkpoint्स की तरह काम कर सकते हैं। जब आप खत्म कर लें, तो source export करना final diff की समीक्षा और साफ़ history रखने में आसान बनाता है।
रिफैक्ट तब बंद करें जब आपके टेस्ट उन पाथ्स को कवर कर लें जिनके टूटने का डर था, अगला बदलाव फीचर होगा, या आपको हर चीज़ को "परफेक्ट" करने की लत लगने लगे। अगर एक बड़े फॉर्म को विभाजन ने tangled state हटाने में मदद की और आपके टेस्ट validation और submit कवर करते हैं, तो शिप करें। बाकी आइडियाज़ को छोटے बैकलॉग के रूप में रखें।
React रिफैक्टर्स अक्सर पहचान और समय/टाइमिंग बदल देते हैं बिना साफ़ संकेत दिए। सामान्य व्यवहार में टूटने के उदाहरण:\n\n- कम्पोनेंट बाउंडरी या key बदल जाने से state रिसेट होना।\n- माउंट/अनमाउंट या बदलती dependencies के कारण effects अलग समय पर चलना।\n- मार्कअप को रैप/स्प्लिट करने के बाद इवेंट हैंडलिंग (focus/blur/keyboard) खिसक जाना।\n\nसंरचनात्मक बदलाव को तब तक व्यवहार बदलने वाला मानें जब तक टेस्ट यह साबित न कर दें कि नहीं।
एक संकुचित, चेक करने लायक लक्ष्य चुनें जो संरचना पर टिके, परिणामों पर नहीं। एक अच्छा लक्ष्य कुछ इस तरह दिखता है:\n\n- “Extract header, rows, and drawer into components with no UI changes.”\n- “Move selection state into one reducer without changing events or props.”\n\n"इसे बेहतर बनाओ" जैसे अस्पष्ट लक्ष्यों से बचें जब तक आपके पास मेट्रिक और ज्ञात बाधा न हो।
कम्पोनेंट को black box की तरह लें और लिखें कि उपयोगकर्ता क्या देखता/करता है:\n\n- कब कौन सा state (loading/empty/error/success) दिखता है\n- डिफ़ॉल्ट्स (selected tab, sort column, initial filter)\n- interaction नियम (फिल्टर बदलने पर क्या रिसेट होता है, क्या फोकस रहता है)\n- फ़ॉर्मैटिंग और ordering नियम (dates, currency, stable sort)\n\nअगर आपके नोट्स बोरिंग और विशिष्ट महसूस हों, तो वे उपयोगी हैं।
Characterization tests जोड़ें जो बताते हैं कि कंपोनेंट आज क्या करता है, भले ही वह अजीब हो।\n\nव्यावहारिक लक्ष्यों पर ध्यान दें:\n\n- किस स्थिति में क्या रेंडर होता है (loading, empty, error)\n- उपयोगकर्ता इंटरैक्शन (typing, pagination, selection)\n- साइड इफेक्ट्स (analytics, URL updates, subscriptions)\n- एसिंक्रोनस सिक्वेंस (पहले spinner, फिर rows/empty/error)\n\nUI में परिणामों को assert करें, न कि आंतरिक हुक कॉल्स को।
इसे एक सावधान pair programmer की तरह उपयोग करें:\n\n- पहले: जिम्मेदारियों का सार और inputs/outputs (props, context, effects) मांगें।\n- फिर: छोटे, commit-आकार के कदमों की योजना मांगें।\n- हर कदम के लिए: बताइए क्या टूट सकता है (state reset, effect timing, event wiring)।\n\nबड़े "रीराइट-स्टाइल" डिफ़ को न स्वीकार करें; छोटे, सत्यापित बदलाव मांगें।
सबसे पहले pure presentation भाग निकालें:\n\n- props इन, JSX आउट\n- कोई नया state या effect नहीं\n- handlers माता-पिता (parent) में रखें और नीचे पास करें\n\nपहले copy-and-wire करें; बाद में cleanup करें। UI को सुरक्षित रूप से विभाजित करने के बाद ही state/effects को अलग करें।
पहचान-आधारित स्थिर keys (ID जैसी) का उपयोग करें, array index नहीं।\n\nIndex keys तब तक काम कर सकते हैं जब तक आप sort/filter/insert/remove न करें—तब React गलत instance reuse कर सकता है और दिखने वाले बग आ सकते हैं:\n\n- गलत row सलेक्टेड रहना\n- इनपुट्स का फोकस खोना या मानों का स्वैप होना\n- लोकल row state गलत आइटम से जुड़ जाना\n\nयदि आपका रिफैक्टर keys बदलता है, तो इसे उच्च जोखिम समझें और reorder केसों की टेस्टिंग करें।
derived values को useState में न रखें जब उन्हें props/state/fetched data से निकाला जा सके।\n\nएक सुरक्षित तरीका:\n\n- केवल user-edited या externally-controlled values को state में रखें\n- derived data (जैसे filteredRows) को rows + query से कम्प्यूट करें\n- महंगे कम्प्यूटेशन के लिए useMemo का उपयोग करें\n\nयह update-संबंधी अजीबताओं को कम करता है और reasoning आसान बनाता है।
checkpoint loop इस्तेमाल करें ताकि हर कदम वापस किया जा सके:\n\n- एक छोटा बदलाव करें (एक extraction या एक effect split)\n- संबंधित characterization tests चलाएँ\n- एक त्वरित मैनुअल “weird path” चेक करें (error → retry → clear filters)\n- एक rollback point सेव करें (git commit या platform snapshot)\n\nयदि आप Koder.ai पर काम कर रहे हैं, तो snapshots और rollback सामान्य commits के साथ सहायक हो सकते हैं।
जब व्यवहार लॉक हो और कोड बदलने में आसान दिखे, तब बंद करें। अच्छे संकेत:\n\n- टेस्ट्स उन पाथ्स को कवर करते हैं जिनके टूटने का डर था\n- अगला बदलाव फीचर जोड़ने जैसा होगा या उत्पाद निर्णय "सुधार" करेगा\n- उसी PR में नामकरण, टाइप्स और आर्किटेक्चर को परफेक्ट करने का मन हो\n\nरिफैक्टर को शिप करें और बाकी आइटम्स को अलग बैकलॉग आइटम बनाकर रखें (accessibility, performance, cleanup)।