Hooks ได้รับการแนะนำให้รู้จักกับ React ในเดือนกุมภาพันธ์ 2019 เพื่อปรับปรุงการอ่านโค้ด เราได้พูดถึง React hooks แล้ว บทความก่อนหน้านี้ แต่คราวนี้เรากำลังตรวจสอบว่า hooks ทำงานกับ TypeScript อย่างไร
อธิบายว่าการออกแบบมีความสำคัญต่อเนื้อหาอย่างไร
ก่อนที่จะมีตะขอส่วนประกอบของปฏิกิริยาเคยมีสองรสชาติ:
การใช้สิ่งเหล่านี้อย่างเป็นธรรมชาติเพื่อสร้างความซับซ้อน ส่วนประกอบภาชนะ ด้วยชั้นเรียนและเรียบง่าย การนำเสนอ ส่วนประกอบที่มีฟังก์ชั่นบริสุทธิ์
ส่วนประกอบคอนเทนเนอร์จัดการการจัดการสถานะและการร้องขอไปยังเซิร์ฟเวอร์ซึ่งจะถูกเรียกในบทความนี้ ผลข้างเคียง . รัฐจะแพร่กระจายไปยังเด็กคอนเทนเนอร์ผ่านอุปกรณ์ประกอบฉาก
แต่เมื่อรหัสเติบโตขึ้น ส่วนประกอบที่ใช้งานได้มักจะถูกเปลี่ยนเป็นส่วนประกอบของคอนเทนเนอร์
การอัปเกรดส่วนประกอบที่ใช้งานได้เป็นอย่างชาญฉลาดนั้นไม่ใช่เรื่องที่น่าเจ็บปวด แต่เป็นงานที่ใช้เวลานานและไม่พึงประสงค์ ยิ่งไปกว่านั้นการแยกแยะผู้นำเสนอและคอนเทนเนอร์ อย่างเคร่งครัด ไม่ต้อนรับอีกต่อไป
ตะขอสามารถทำได้ทั้งสองอย่าง ดังนั้นโค้ดที่ได้จึงมีความสม่ำเสมอมากขึ้นและมีประโยชน์เกือบทั้งหมด นี่คือตัวอย่างของการเพิ่มสถานะท้องถิ่นให้กับส่วนประกอบขนาดเล็กที่จัดการลายเซ็นใบเสนอราคา
// put signature in local state and toggle signature when signed changes function QuotationSignature({quotation}) { const [signed, setSigned] = useState(quotation.signed); useEffect(() => { fetchPost(`quotation/${quotation.number}/sign`) }, [signed]); // effect will be fired when signed changes return {setSigned(!signed)}}/> Signature }
มีโบนัสใหญ่สำหรับสิ่งนี้ - การเข้ารหัสด้วย TypeScript ดีมากกับ Angular แต่ป่องด้วย React อย่างไรก็ตามการเข้ารหัส ตอบสนอง hooks ด้วย TypeScript เป็นประสบการณ์ที่น่าพอใจ
TypeScript ได้รับการออกแบบโดย Microsoft และเป็นไปตามเส้นทาง Angular เมื่อ React พัฒนาขึ้น ไหล ซึ่งตอนนี้กำลังสูญเสียแรงฉุด การเขียนคลาส React ด้วย TypeScript ที่ไร้เดียงสานั้นค่อนข้างเจ็บปวดเพราะ ตอบสนองนักพัฒนา ต้องพิมพ์ทั้งสอง props
และ state
แม้ว่าจะมีหลายปุ่มเหมือนกัน
นี่คือวัตถุโดเมนง่ายๆ เราทำไฟล์ แอพใบเสนอราคา , ด้วย Quotation
ประเภทจัดการในส่วนประกอบ crud บางส่วนที่มีสถานะและอุปกรณ์ประกอบฉาก Quotation
สามารถสร้างได้และสถานะที่เกี่ยวข้องสามารถเปลี่ยนเป็นเซ็นหรือไม่ก็ได้
interface Quotation{ id: number title:string; lines:QuotationLine[] price: number } interface QuotationState{ readonly quotation:Quotation; signed: boolean } interface QuotationProps{ quotation:Quotation; } class QuotationPage extends Component { // ... }
แต่ลองนึกภาพ QuotationPage ตอนนี้จะขอไฟล์ id : ตัวอย่างเช่นใบเสนอราคา 678 ที่จัดทำโดย บริษัท นั่นหมายความว่า QuotationProps ไม่ทราบตัวเลขที่สำคัญนั่นไม่ใช่การตัดใบเสนอราคา เป๊ะ . เราต้องประกาศรหัสเพิ่มเติมอีกมากมายในอินเทอร์เฟซ QuotationProps:
interface QuotationProps{ // ... all the attributes of Quotation but id title:string; lines:QuotationLine[] price: number }
เราคัดลอกแอตทริบิวต์ทั้งหมดยกเว้น id ในประเภทใหม่ หืม นั่นทำให้ฉันนึกถึง Java แบบเก่าซึ่งเกี่ยวข้องกับการเขียน DTO จำนวนมาก เพื่อเอาชนะสิ่งนั้นเราจะเพิ่มความรู้ TypeScript ของเราเพื่อหลีกเลี่ยงความเจ็บปวด
ด้วยการใช้ตะขอเราจะสามารถกำจัดอินเทอร์เฟซ QuotationState ก่อนหน้านี้ได้ ในการทำเช่นนี้เราจะแบ่ง QuotationState ออกเป็นสองส่วนที่แตกต่างกันของรัฐ
interface QuotationProps{ quotation:Quotation; } function QuotationPage({quotation}:QuotationProps){ const [quotation, setQuotation] = useState(quotation); const [signed, setSigned] = useState(false); }
เราไม่จำเป็นต้องสร้างอินเทอร์เฟซใหม่ด้วยการแยกสถานะ ประเภทของรัฐในพื้นที่มักจะอนุมานโดยค่าสถานะเริ่มต้น
ส่วนประกอบที่มีตะขอเป็นฟังก์ชันทั้งหมด ดังนั้นเราสามารถเขียนส่วนประกอบเดียวกันที่ส่งคืน เห็นได้ชัดว่าการใช้ TypeScript กับ React hooks นั้นง่ายกว่าการใช้กับคลาส React และเนื่องจากการพิมพ์ที่รัดกุมเป็นการรักษาความปลอดภัยที่มีค่าสำหรับความปลอดภัยของโค้ดคุณควรพิจารณาใช้ TypeScript หากโปรเจ็กต์ใหม่ของคุณใช้ hooks คุณควรใช้ hooks อย่างแน่นอนหากคุณต้องการ TypeScript บางอย่าง มีสาเหตุหลายประการที่คุณสามารถหลีกเลี่ยง TypeScript โดยใช้ React หรือไม่ แต่ถ้าคุณจะเลือกใช้ก็ควรใช้ตะขอด้วยเช่นกัน ในตัวอย่าง TypeScript ของ React hooks ก่อนหน้านี้ฉันยังมีแอตทริบิวต์ number ใน QuotationProps แต่ยังไม่มีเงื่อนงำว่าแท้จริงแล้วตัวเลขนั้นคืออะไร TypeScript ให้รายการไฟล์ ประเภทยูทิลิตี้ และสามคนจะช่วยเราในการตอบสนองโดยการลดเสียงรบกวนของคำอธิบายอินเทอร์เฟซจำนวนมาก ในกรณีของเราเราต้องการ ตอนนี้เรามีใบเสนอราคาที่ไม่มีรหัส ดังนั้นบางทีเราอาจออกแบบ อย่างไรก็ตามตอนนี้เรามั่นใจแล้วว่าเราจะไม่แพร่กระจายวัตถุที่เราคิดว่ามี หรือเพียงแค่: อย่าตัดสินฉันฉันเป็นแฟนตัวยงของ Domain Driven Design ฉันไม่ขี้เกียจถึงขนาดที่ว่าฉันไม่ต้องการเขียนเพิ่มอีกสองบรรทัดสำหรับอินเทอร์เฟซใหม่ ฉันใช้อินเทอร์เฟซสำหรับการอธิบายชื่อโดเมนอย่างแม่นยำและฟังก์ชันยูทิลิตี้เหล่านี้เพื่อความถูกต้องของรหัสในเครื่องโดยหลีกเลี่ยงเสียงรบกวน ผู้อ่านจะรู้ว่า ทีม React มักจะมองและถือว่า React เป็นกรอบการทำงาน พวกเขาใช้คลาสเพื่อให้ส่วนประกอบสามารถจัดการกับสถานะของตัวเองได้และตอนนี้ hooks เป็นเทคนิคที่ช่วยให้ฟังก์ชันสามารถติดตามสถานะของส่วนประกอบได้ นี่คือกรณีที่ใช้ แม้ว่าฟังก์ชันสามารถเรียกใช้งานได้หลายครั้ง แต่ฟังก์ชัน โดย ตามธรรมชาติ การแยกฟังก์ชันตัวลดออกจากส่วนประกอบรหัสสามารถแบ่งออกเป็นฟังก์ชันอิสระหลายฟังก์ชันแทนที่จะเป็นฟังก์ชันหลายฟังก์ชันภายในคลาสซึ่งทั้งหมดเชื่อมโยงกับสถานะภายในคลาส สิ่งนี้ดีกว่าอย่างชัดเจนสำหรับความสามารถในการทดสอบ - ฟังก์ชันบางอย่างจัดการกับ JSX, อื่น ๆ ที่มีพฤติกรรม, อื่น ๆ ที่มีตรรกะทางธุรกิจและอื่น ๆ คุณ (เกือบ) ไม่จำเป็นต้องใช้ส่วนประกอบที่สูงขึ้นอีกต่อไป รูปแบบอุปกรณ์แสดงผลนั้นง่ายกว่าในการเขียนด้วยฟังก์ชัน ดังนั้นการอ่านรหัสจึงง่ายกว่า รหัสของคุณไม่ใช่โฟลว์ของคลาส / ฟังก์ชัน / รูปแบบ แต่เป็นโฟลว์ของฟังก์ชัน อย่างไรก็ตามเนื่องจากฟังก์ชันของคุณไม่ได้ยึดติดกับวัตถุจึงอาจเป็นเรื่องยากที่จะตั้งชื่อฟังก์ชันเหล่านี้ทั้งหมด JavaScript เป็นเรื่องสนุกเพราะคุณสามารถฉีกโค้ดของคุณได้ทุกทิศทาง ด้วย TypeScript คุณยังสามารถใช้ แต่คุณสามารถทำได้อย่างปลอดภัย ให้แน่ใจว่า มีการถกเถียงกันเกี่ยวกับระดับการพิมพ์ที่คุณใส่ในรหัสของคุณ คุณสามารถพิมพ์ทุกอย่างหรือปล่อยให้คอมไพเลอร์สรุปประเภท ขึ้นอยู่กับการกำหนดค่า linter และตัวเลือกของทีม นอกจากนี้คุณยังสามารถสร้างข้อผิดพลาดรันไทม์ได้! TypeScript นั้นง่ายกว่า Java และหลีกเลี่ยงปัญหาความแปรปรวนร่วม / ความขัดแย้งด้วย Generics ใน ตัวอย่างสัตว์ / แมวนี้ เรามีรายการสัตว์ที่เหมือนกับรายการแมว น่าเสียดายที่มันเป็นสัญญาในบรรทัดแรกไม่ใช่ที่สอง จากนั้นเราเพิ่มเป็ดในรายการสัตว์ดังนั้นรายชื่อแมวจึงเป็นเท็จ TypeScript มีเพียงไฟล์ ไบวาเรียน แนวทางสำหรับ generics ที่เรียบง่ายและช่วยให้นักพัฒนา JavaScript นำไปใช้ หากคุณตั้งชื่อตัวแปรอย่างถูกต้องคุณจะไม่ค่อยเพิ่ม นอกจากนี้ยังมีข้อเสนอสำหรับการเพิ่ม สัญญาเข้าและออก สำหรับความแปรปรวนร่วมและความแตกต่าง ฉันเพิ่งกลับมาที่ Kotlin ซึ่งเป็นภาษาที่ดีและมีความซับซ้อนในการพิมพ์ชื่อสามัญที่ซับซ้อนให้ถูกต้อง คุณไม่มีความซับซ้อนทั่วไปขนาดนั้นกับ TypeScript เนื่องจากความเรียบง่ายของการพิมพ์แบบเป็ดและวิธีการแบบสองตัวแปร แต่คุณมีปัญหาอื่น ๆ บางทีคุณอาจไม่พบปัญหามากนักกับ Angular ซึ่งออกแบบมาพร้อมกับ TypeScript แต่คุณมีคลาส React TypeScript น่าจะเป็นผู้ชนะที่ยิ่งใหญ่ของปี 2019 มันได้รับ React แต่ยังพิชิตโลกหลังสุดด้วย Node.js และความสามารถในการพิมพ์ไลบรารีเก่าด้วยค่อนข้างง่าย ไฟล์ประกาศ . มันฝังกระแสแม้ว่าบางส่วนจะดำเนินไป ตลอดทางด้วย ReasonML . ตอนนี้ฉันรู้สึกว่า hooks + TypeScript นั้นน่าพอใจและมีประสิทธิผลมากกว่า Angular ฉันไม่คิดว่าหกเดือนที่แล้ว ตอนนี้ TypeScript ดีมากสำหรับ React ถ้าคุณใช้ hooks ด้วย TypeScript ให้ความปลอดภัยของรหัส IDE ทำให้คุณมีข้อผิดพลาดเกี่ยวกับโค้ดมากที่สุดดังนั้นคุณจึงใช้เวลาน้อยลงในการดีบักแอปในคอนโซล React Hooks ช่วยลดความซับซ้อนของการพัฒนาโค้ดและการบำรุงรักษา ตะขอยังมีชุดรูปแบบทั่วไปสำหรับปัญหาทั่วไป คอนเทนเนอร์มีตรรกะทางธุรกิจไม่ใช่ส่วนประกอบ แตกต่างจากคอนเทนเนอร์ตรงที่สามารถใช้ส่วนประกอบต่างๆในส่วนต่างๆของแอปได้แม้ในแอปต่างๆFC
const QuotationPage : FC = ({quotation}) => { const [quotation, setQuotation] = useState(quotation); const [signed, setSigned] = useState(false); }
คุณสมบัติเฉพาะของ TypeScript เหมาะสำหรับ Hooks
Partial
: ปุ่มย่อยใด ๆ ของ TOmit
: คีย์ทั้งหมดของ T ยกเว้นคีย์ x
Pick
: ตรง x, y, z
คีย์จาก T
Omit
เพื่อละเว้น id ของใบเสนอราคา เราสามารถสร้างรูปแบบใหม่ได้ทันทีด้วย type
คำสำคัญ.Partial
และ Omit
ไม่มีอยู่ในภาษาพิมพ์ส่วนใหญ่เช่น Java แต่ช่วยได้มากสำหรับตัวอย่างด้วย Forms ในการพัฒนาส่วนหน้า ช่วยลดความยุ่งยากในการพิมพ์type QuotationProps= Omit; function QuotationPage({quotation}:QuotationProps){ const [quotation, setQuotation] = useState(quotation); const [signed, setSigned] = useState(false); // ... }
Quotation
และ PersistedQuotation
extends
Quotation
. นอกจากนี้เราจะแก้ไขปัญหาซ้ำ if
ได้อย่างง่ายดาย หรือ undefined
ปัญหา. เรายังควรเรียกคำพูดของตัวแปรแม้ว่ามันจะไม่ใช่วัตถุเต็ม? ซึ่งอยู่นอกเหนือขอบเขตของบทความนี้ แต่เราจะกล่าวถึงในภายหลังnumber
ใช้ Partial
ไม่ได้นำการค้ำประกันเหล่านี้ทั้งหมดมาใช้ดังนั้นโปรดใช้ดุลยพินิจPick
เป็นอีกวิธีหนึ่งในการประกาศประเภทได้ทันทีโดยไม่ต้องมีการประกาศอินเทอร์เฟซใหม่ หากส่วนประกอบเพียงแก้ไขชื่อใบเสนอราคา:type QuoteEditFormProps= Pick
function QuotationNameEditor({id, title}:Pick){ ...}
Quotation
คืออินเทอร์เฟซมาตรฐานประโยชน์อื่น ๆ ของ React Hooks
interface Place{ city:string, country:string } const initialState:Place = { city: 'Rosebud', country: 'USA' }; function reducer(state:Place, action):Partial { switch (action.type) { case 'city': return { city: action.payload }; case 'country': return { country: action.payload }; } } function PlaceForm() { const [state, dispatch] = useReducer(reducer, initialState); return ( { dispatch({ type: 'city',payload: event.target.value}) }} value={state.city} /> { dispatch({type: 'country', payload: event.target.value }) }} value={state.country} /> ); }
Partial
ปลอดภัยและเป็นทางเลือกที่ดีuseReducer
ที่เกี่ยวข้อง เบ็ดจะถูกสร้างขึ้นเพียงครั้งเดียวTypeScript ยังคงเป็น JavaScript
keyof
เพื่อเล่นกับกุญแจของวัตถุ คุณสามารถใช้ยูเนี่ยนประเภทเพื่อสร้างสิ่งที่อ่านไม่ได้และไม่สามารถเข้าถึงได้ - ไม่ฉันไม่ชอบสิ่งเหล่านั้น คุณสามารถใช้นามแฝงประเภทเพื่อหลอกว่าสตริงเป็น UUIDtsconfig.json
ของคุณ มี 'strict':true
ตัวเลือก ตรวจสอบก่อนเริ่มโครงการไม่เช่นนั้นคุณจะต้อง refactor เกือบทุกบรรทัด!interface Animal {} interface Cat extends Animal { meow: () => string; } const duck = {age: 7}; const felix = { age: 12, meow: () => 'Meow' }; const listOfAnimals: Animal[] = [duck]; const listOfCats: Cat[] = [felix]; function MyApp() { const [cats , setCats] = useState(listOfCats); // Here the thing: listOfCats is declared as a Animal[] const [animals , setAnimals] = useState(listOfCats) const [animal , setAnimal] = useState(duck) return { animals.unshift(animal) // we set as first cat a duck ! setAnimals([...animals]) // dirty forceUpdate } }> The first cat says {cats[0].meow()} ; }
duck
ถึง a listOfCats
..hpp กับ .cpp
สรุป
ทำความเข้าใจพื้นฐาน
ฉันสามารถใช้ TypeScript กับ React ได้หรือไม่
TypeScript มีประโยชน์อย่างไร?
อะไรคือเรื่องใหญ่กับ React Hooks?
อะไรคือความแตกต่างระหว่างคอนเทนเนอร์และส่วนประกอบ?