why-did-you-render
โดยซอฟต์แวร์ลิง Welldone Software React
เพื่อแจ้งให้คุณทราบเกี่ยวกับการเรนเดอร์ซ้ำที่อาจหลีกเลี่ยงได้ (ใช้ได้กับ React Native
เช่นกัน)
ตัวอย่างเช่น หากคุณส่ง style={{width: '100%'}}
ไปยังองค์ประกอบบริสุทธิ์ขนาดใหญ่ มันจะแสดงผลซ้ำทุกครั้งที่สร้างองค์ประกอบทุกครั้ง:
<BigListPureComponent style={{ความกว้าง: '100%'}}/>
นอกจากนี้ยังช่วยให้คุณติดตามได้ง่ายว่าเมื่อใดและเพราะเหตุใดส่วนประกอบบางอย่างจึงแสดงผลซ้ำ
เวอร์ชันล่าสุดของไลบรารีได้รับการทดสอบ (การทดสอบหน่วยและ E2E) ด้วย React@18
เท่านั้น สำหรับ React 17 และ 16 โปรดใช้เวอร์ชัน @^7
npm install @welldone-software/why-did-you-render --save-dev
หรือ
yarn add --dev @welldone-software/why-did-you-render
หากคุณใช้การแปลง JSX automatic
ให้ตั้งค่าไลบรารีให้เป็นแหล่งการนำเข้า และตรวจสอบให้แน่ใจว่า preset-react
อยู่ในโหมด development
['@babel/preset-react', { รันไทม์: 'อัตโนมัติ', การพัฒนา: process.env.NODE_ENV === 'การพัฒนา', importSource: '@welldone-software/why-did-you-render',}]
น่าเสียดายที่ metro-react-native-babel-preset
ที่มาพร้อมกับ react-native ไม่อนุญาตให้คุณเปลี่ยนตัวเลือกของปลั๊กอิน babel/plugin-transform-react-jsx
เพียงเพิ่มปลั๊กอินพร้อมตัวเลือกตามรายการด้านล่างและเริ่ม react-native packager ตามปกติ env เริ่มต้นสำหรับ babel คือ "การพัฒนา" หากคุณไม่ได้ใช้ expo เมื่อทำงานกับ react-native วิธีการต่อไปนี้จะช่วยคุณได้
module.exports = { ที่ตั้งไว้ล่วงหน้า: ['โมดูล:metro-react-native-babel-preset'], env: { การพัฒนา: { ปลั๊กอิน: [['@babel/plugin-transform-react-jsx', { รันไทม์: ' คลาสสิก' }]], }, },}
คุณสามารถส่งพารามิเตอร์ไปที่ @babel/preset-react
ผ่าน babel-preset-expo
// babel.config.jsmodule.exports = function (api) { api.cache(true); return { presets: [ [ "babel-preset-expo", { jsxImportSource: "@welldone-software/why-did-you-render", }, ], ], };};
หมายเหตุ: สร้างแอป React (CRA) ^4 ใช้การแปลง JSX
automatic
ดูความคิดเห็นต่อไปนี้เกี่ยวกับวิธีการทำตามขั้นตอนนี้กับ CRA
สร้างไฟล์ wdyr.js
และนำเข้าเป็น การนำเข้าครั้งแรก ในแอปพลิเคชันของคุณ
wdyr.js
:
นำเข้า React จาก 'react';if (process.env.NODE_ENV === 'การพัฒนา') { const whyDidYouRender = need('@welldone-software/why-did-you-render'); whyDidYouRender (ตอบสนอง, { trackAllPureComponents: true, });}
หมายเหตุ: ไม่ ควรใช้ไลบรารีในการผลิตเนื่องจากจะทำให้ React ช้าลง
ใน Typescript ให้เรียกไฟล์ wdyr.ts และเพิ่มบรรทัดต่อไปนี้ที่ด้านบนของไฟล์เพื่อนำเข้าประเภทของแพ็คเกจ:
/// <reference types="@welldone-software/why-did-you-render" />
นำเข้า wdyr
เป็นการนำเข้าครั้งแรก (แม้กระทั่งก่อน react-hot-loader
):
index.js
:
นำเข้า './wdyr'; // <--- นำเข้าครั้งแรก 'react-hot-loader'; นำเข้า {hot} จาก 'react-hot-loader/root'; นำเข้า React จาก 'react'; นำเข้า ReactDOM จาก 'react-dom';// ..นำเข้า {App} จาก './app';// ...const HotApp = hot(App);// ...ReactDOM.render(<HotApp/>, document.getElementById('root'));
หากคุณใช้ trackAllPureComponents
ตามที่เราแนะนำ ส่วนประกอบล้วนๆ ทั้งหมด (React.PureComponent หรือ React.memo) จะถูกติดตาม
มิฉะนั้น ให้เพิ่ม whyDidYouRender = true
ให้กับคลาส/ฟังก์ชันส่วนประกอบที่คุณต้องการติดตาม (fe Component.whyDidYouRender = true
)
ข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่ถูกติดตามสามารถพบได้ในองค์ประกอบการติดตาม
ไม่เห็นบันทึก WDYR ใด ๆ ใช่ไหม ตรวจสอบส่วนการแก้ไขปัญหาหรือค้นหาในปัญหา
นอกจากนี้ การติดตาม hooks แบบกำหนดเองยังสามารถทำได้โดยใช้ trackExtraHooks
ตัวอย่างเช่น หากคุณต้องการติดตาม useSelector
จาก React Redux:
wdyr.js
:
นำเข้า React จาก 'react';// สำหรับ react-native คุณอาจต้องการใช้ // แฟล็ก __DEV__ แทน process.env.NODE_ENV === 'development'if (process.env.NODE_ENV === 'development') { const whyDidYouRender = need('@welldone-software/why-did-you-render'); const ReactRedux = ต้องการ ('react-redux'); whyDidYouRender (ตอบสนอง, { trackAllPureComponents: true, trackExtraHooks: [ [ReactRedux, 'useSelector'] ] });}
โปรดสังเกตว่าขณะนี้มีปัญหาในการเขียนการส่งออกไฟล์ที่นำเข้าใน
webpack
วิธีแก้ปัญหาด่วนสามารถช่วยได้: #85 - trackExtraHooks ไม่สามารถตั้งค่าคุณสมบัติได้
ทำไมคุณถึงเรนเดอร์ Mr. Big Pure React Component???
สถานการณ์การแก้ไขทั่วไป ที่ไลบรารีนี้สามารถช่วยได้
React Hooks - ทำความเข้าใจและแก้ไขปัญหา hooks
เหตุใดคุณจึง Render v4 เปิดตัว! - รองรับ TypeScript, การติดตาม hooks แบบกำหนดเอง (เช่น useSelector ของ React-Redux), การติดตามส่วนประกอบที่แท้จริงทั้งหมด
ตัวอย่าง Next.js
ทำปฏิกิริยา Redux ด้วยตะขอ
Mobx ยังไม่รองรับในขณะนี้
ปลั๊กอินฟลิปเปอร์ React-Native สร้างโดย @allen-hsu
คุณสามารถทดสอบไลบรารีได้ในแซนด์บ็อกซ์อย่างเป็นทางการ
และแซนด์บ็อกซ์อย่างเป็นทางการอีกอันพร้อมการติดตามตะขอ
คุณสามารถติดตามส่วนประกอบที่แท้จริงทั้งหมด (React.PureComponent หรือ React.memo) ได้โดยใช้ตัวเลือก trackAllPureComponents: true
คุณยังสามารถติดตามส่วนประกอบใด ๆ ที่คุณต้องการได้ด้วยตนเองโดยตั้งค่า whyDidYouRender
ให้กับองค์ประกอบเหล่านั้นดังนี้:
class BigList ขยาย React.Component { static whyDidYouRender = true render(){ return ( // การเรนเดอร์จำนวนมากที่คุณต้องการให้แน่ใจว่าจะไม่เกิดขึ้นหากไม่จำเป็น ) }}
หรือสำหรับส่วนประกอบที่ใช้งานได้:
const BigListPureComponent = อุปกรณ์ประกอบฉาก => ( <div> //ส่วนประกอบหนักๆ บางอย่างที่คุณต้องการให้แน่ใจว่าจะไม่เกิดขึ้นหากไม่จำเป็น </div>)BigListPureComponent.whyDidYouRender = true
คุณยังสามารถส่งผ่านออบเจ็กต์เพื่อระบุการตั้งค่าการติดตามขั้นสูงเพิ่มเติมได้:
EnhancedMenu.whyDidYouRender = { logOnDifferentValues: true, customName: 'Menu'}
logOnDifferentValues
:
โดยปกติแล้ว เฉพาะการเรนเดอร์ซ้ำที่เกิดจากค่าที่เท่ากันในการแจ้งเตือนทริกเกอร์อุปกรณ์ประกอบฉาก / สถานะ:
render(<เมนู a={1}/>)render(<เมนู a={1}/>)
ตัวเลือกนี้จะทริกเกอร์การแจ้งเตือนแม้ว่าจะเกิดขึ้นเนื่องจากอุปกรณ์ประกอบฉาก / สถานะที่แตกต่างกัน (ดังนั้นเนื่องจากการเรนเดอร์ซ้ำ "ถูกต้อง"):
render(<เมนู a={1}/>)render(<เมนู a={2}/>)
customName
:
บางครั้งชื่อของส่วนประกอบอาจหายไปหรือไม่สะดวกอย่างมาก ตัวอย่างเช่น:
withPropsOnChange(withPropsOnChange(withStateHandlers(withPropsOnChange(withState(withPropsOnChange(วงจรชีวิต(withPropsOnChange(withPropsOnChange(onlyUpdateForKeys(LoadNamesp) ace (เชื่อมต่อ (withState (withState (withPropsOnChange (วงจรชีวิต (withPropsOnChange (withHandlers (withHandlers (withHandlers (withHandlers (เชื่อมต่อ (วงจรชีวิต (เมนู)))))))))))))))))))))))))
คุณสามารถเลือกส่ง options
เป็นพารามิเตอร์ตัวที่สองได้ มีตัวเลือกต่อไปนี้:
include: [RegExp, ...]
( null
โดยค่าเริ่มต้น)
exclude: [RegExp, ...]
( null
โดยค่าเริ่มต้น)
trackAllPureComponents: false
trackHooks: true
trackExtraHooks: []
logOwnerReasons: true
logOnDifferentValues: false
hotReloadBufferMs: 500
onlyLogs: false
collapseGroups: false
titleColor
diffNameColor
diffPathColor
notifier: ({Component, displayName, hookName, prevProps, prevState, prevHook, nextProps, nextState, nextHook, reason, options, ownerDataMap}) => void
getAdditionalOwnerData: (element) => {...}
null
) คุณสามารถรวมหรือยกเว้นการติดตามส่วนประกอบตามชื่อที่แสดงได้โดยใช้ตัวเลือก include
และ exclude
ตัวอย่างเช่น รหัสต่อไปนี้ใช้เพื่อติดตามการเรนเดอร์ซ้ำซ้ำซ้อนทั้งหมดที่เกิดจาก React-Redux รุ่นเก่า:
whyDidYouRender (ตอบสนอง, { รวม: [/^ConnectFunction/] });
หมายเหตุ: ไม่รวม ลำดับความสำคัญมากกว่าทั้ง
include
และตั้งค่าwhyDidYouRender =
ด้วยตนเอง
false
) คุณสามารถติดตามส่วนประกอบที่แท้จริงทั้งหมดได้ (ทั้งส่วนประกอบ React.memo
และ React.PureComponent
)
หมายเหตุ: คุณสามารถยกเว้นการติดตามองค์ประกอบเฉพาะใดๆ ด้วย
whyDidYouRender = false
true
)คุณสามารถปิดการติดตามการเปลี่ยนแปลง hooks ได้
ทำความเข้าใจและแก้ไขปัญหาเกี่ยวกับตะขอ
[]
)ติดตาม hooks แบบกำหนดเอง:
whyDidYouRender(React, { trackExtraHooks: [ // สังเกตว่า 'useSelector' เป็นการส่งออกที่มีชื่อ [ReactRedux, 'useSelector'], ]});
ขณะนี้มีปัญหาในการเขียนการส่งออกไฟล์ที่นำเข้าใน webpack ใหม่ วิธีแก้ปัญหามีอยู่ที่นี่: #85 - trackExtraHooks ไม่สามารถตั้งค่าคุณสมบัติได้
true
)วิธีหนึ่งในการแก้ไขปัญหาการเรนเดอร์ซ้ำคือการป้องกันไม่ให้เจ้าของคอมโพเนนต์เรนเดอร์ซ้ำ
ตัวเลือกนี้เป็น true
ตามค่าเริ่มต้น และช่วยให้คุณดูสาเหตุที่คอมโพเนนต์ของเจ้าของแสดงผลซ้ำได้
false
)โดยปกติ คุณต้องการเฉพาะบันทึกเกี่ยวกับการเรนเดอร์ส่วนประกอบซ้ำเมื่อสามารถหลีกเลี่ยงได้
ด้วยตัวเลือกนี้ คุณสามารถติดตามการเรนเดอร์ซ้ำทั้งหมดได้
ตัวอย่างเช่น:
render(<BigListPureComponent a={1}/>)render(<BigListPureComponent a={2}/>)// จะบันทึกเฉพาะเมื่อคุณใช้ {logOnDifferentValues: true}
500
)เวลาเป็นมิลลิวินาทีที่จะเพิกเฉยต่อการอัปเดตหลังจากตรวจพบการรีโหลดแบบ hot
เมื่อตรวจพบการรีโหลดแบบ hot เราจะเพิกเฉยต่อการอัปเดตทั้งหมดสำหรับ hotReloadBufferMs
เพื่อไม่ส่งสแปมคอนโซล
false
) หากคุณไม่ต้องการใช้ console.group
เพื่อจัดกลุ่มบันทึก คุณสามารถพิมพ์เป็นบันทึกธรรมดาได้
false
)บันทึกที่จัดกลุ่มสามารถยุบได้
'#058'
)'blue'
)'red'
)ควบคุมสีที่ใช้ในการแจ้งเตือนของคอนโซล
คุณสามารถสร้างการแจ้งเตือนแบบกำหนดเองได้หากค่าเริ่มต้นไม่ตรงกับความต้องการของคุณ
undefined
)คุณสามารถจัดเตรียมฟังก์ชันที่รวบรวมข้อมูลเพิ่มเติมจากองค์ประกอบปฏิกิริยาดั้งเดิมได้ วัตถุที่ส่งคืนจากฟังก์ชันนี้จะถูกเพิ่มใน OwnerDataMap ซึ่งสามารถเข้าถึงได้ในภายหลังภายในการแทนที่ฟังก์ชันตัวแจ้งเตือนของคุณ
หากคุณอยู่ในการใช้งานจริง WDYR อาจถูกปิดใช้งาน
อาจไม่มีการติดตามส่วนประกอบใดๆ
ตรวจสอบองค์ประกอบการติดตามอีกครั้ง
หากคุณติดตามส่วนประกอบที่แท้จริงโดยใช้ trackAllPureComponents: true
คุณจะติดตามเพียงอย่างใดอย่างหนึ่งเท่านั้น (React.PureComponent หรือ React.memo) อาจจะไม่มีส่วนประกอบใดของคุณที่บริสุทธิ์ ดังนั้นจึงไม่มีองค์ประกอบใดที่จะถูกติดตาม
บางทีคุณอาจไม่มีปัญหา
ลองทำให้เกิดปัญหาโดยแสดงผลทั้งแอปชั่วคราวสองครั้งในจุดเริ่มต้น:
index.js
:
const HotApp = hot(App);HotApp.whyDidYouRender = true;ReactDOM.render(<HotApp/>, document.getElementById('root'));ReactDOM.render(<HotApp/>, document.getElementById('root') );
ขณะนี้มีปัญหาในการเขียนการส่งออกไฟล์ที่นำเข้าใน webpack
วิธีแก้ปัญหาด่วนสามารถช่วยได้: #85 - trackExtraHooks ไม่สามารถตั้งค่าคุณสมบัติได้
connect
HOC กำลังส่งสแปมคอนโซล เนื่องจาก connect
แบบคงที่ของรอก หากคุณเพิ่ม WDYR ให้กับส่วนประกอบภายใน ก็จะถูกเพิ่มไปยังส่วนประกอบ HOC ที่มีการทำงานของ hook ที่ซับซ้อนอยู่ด้วย
หากต้องการแก้ไขปัญหานี้ ให้เพิ่ม whyDidYouRender = true
static ให้กับส่วนประกอบหลังการเชื่อมต่อ:
const SimpleComponent = ({a}) => <div data-testid="foo">{ab}</div>) // ไม่ใช่ก่อนการเชื่อมต่อ: // SimpleComponent.whyDidYouRender = true const ConnectedSimpleComponent = เชื่อมต่อ ( state => ({a: state.a}) )(SimpleComponent) // หลังจากการเชื่อมต่อ: SimpleComponent.whyDidYouRender = true
หากต้องการดูซอร์สแมปของไลบรารี ให้ใช้ซอร์สแมปโหลดเดอร์
แรงบันดาลใจจากงานก่อนหน้านี้ดังต่อไปนี้:
github.com/maicki/why-did-you-update (ไม่เปิดเผยต่อสาธารณะอีกต่อไป) ซึ่งฉันมีโอกาสรักษามาระยะหนึ่งแล้ว
https://github.com/garbles/why-did-you-update โดยที่การดำน้ำลึกเกี่ยวกับการดีบัก React perf นั้นให้เครดิตสำหรับแนวคิดนี้
ห้องสมุดนี้ได้รับอนุญาตจาก MIT