สร้างแอปพลิเคชัน React ตั้งแต่เริ่มต้น (ตอนที่ 7): การตั้งค่า React และ Best Practices

โพสต์นี้เป็นส่วนหนึ่งของชุดโพสต์ระดับเริ่มต้นสำหรับผู้ที่ใช้
เครื่องมือแม่แบบหรือแม่แบบสำเร็จรูปสำหรับ React แต่ต้องการเรียนรู้และเข้าใจวิธีการสร้างแอปพลิเคชัน React ตั้งแต่เริ่มต้น

โพสต์ทั้งหมดในชุดนี้:
ตอนที่ 1: บทนำ
ส่วนที่ 2: การเริ่มต้นและไฟล์แรก
ส่วนที่ 3: การใช้ไวยากรณ์ ES2015
ตอนที่ 4: การบังคับใช้คู่มือสไตล์
ส่วนที่ 5: การตั้งค่าเซิร์ฟเวอร์ด่วน
ตอนที่ 6: การใช้โมดูล Bundler
ตอนที่ 7: การตั้งค่าการตอบสนองและแนวทางปฏิบัติที่ดีที่สุด
ตอนที่ 8: การตั้งค่า Redux
ส่วนที่ 9: การตั้งค่าเราเตอร์โต้ตอบ
ตอนที่ 10: TDD และการตั้งค่าความตลกขบขัน

การตั้งค่า React

ในบทความนี้เราจะทำการติดตั้ง React และสร้างองค์ประกอบที่ง่ายมากจากนั้นเราจะทำตามแนวทางปฏิบัติที่ดีที่สุดที่คุณควรคำนึงถึงเมื่อพัฒนาส่วนประกอบของ React นี่คือจุดเริ่มต้นของความสนุกดังนั้นให้เราขุดลงไป!

ติดตั้งแพคเกจ React และ React Dom เป็นการอ้างอิง:

$ npm install - บันทึกการตอบสนอง react-dom

จากนั้นเปิด index.js และสร้างองค์ประกอบ React ที่ง่ายมากซึ่งแสดงถึงแอปพลิเคชันของเรา เรามีองค์ประกอบที่มีแอพ id ในไฟล์เทมเพลต index.pug ของเราดังนั้นให้เราใช้มันเพื่อเมาท์แอพ

/ **
 * index.js
 * /
นำเข้าปฏิกิริยาจาก 'ปฏิกิริยา';
นำเข้า {render} จาก 'react-dom';
const MainApp = () => (
  

สวัสดีตอบโต้!

);
// แสดงแอพ
แสดงผล (, document.getElementById ('แอป'));

รหัสง่าย ๆ นี้สร้างองค์ประกอบการทำงานที่ไร้สัญชาติ MainApp และประกอบเข้ากับองค์ประกอบ DOM ที่มีแอพ id รหัสนี้จะไม่ทำงานทันทีและคุณจะได้รับข้อผิดพลาดหากคุณพยายามสร้างมัดหรือเริ่มเซิร์ฟเวอร์

สาเหตุของข้อผิดพลาดนี้คือเรามีไวยากรณ์ JSX ในไฟล์ index.js ซึ่ง Babel ยังไม่เข้าใจ เพื่อให้ Babel ตีความไวยากรณ์นี้เป็น JavaScript ปกติเราจะใช้ React preset สำหรับ Babel

ติดตั้งแพคเกจเป็นการอ้างอิง:

$ npm ติดตั้ง - บันทึก babel-preset-react

จากนั้นเพิ่มค่าที่ตั้งไว้ล่วงหน้าลงในรายการค่าที่ตั้งไว้ในไฟล์. babelrc:

{
  "ค่าที่ตั้งล่วงหน้า": [
    "es2015"
    "เวที-0"
    "ตอบสนอง"
  ]
  "ปลั๊กอิน": ["transform-inline-environment-variables"]
}

ควรมีข้อผิดพลาดที่เป็นขุยที่จะป้องกันคุณจากการสร้างมัด linter กำลังบ่นเนื่องจาก index.js เป็นไฟล์ JavaScript ที่มีไวยากรณ์ JSX แต่ใช้ส่วนขยาย js แทน jsx

คุณสามารถอ่านคำอธิบายสำหรับกฎนี้ได้ที่นี่ ส่วน ‘เมื่อไม่ใช้’ บอกว่าคุณไม่ควรใช้กฎนี้หากคุณไม่สนใจที่จะ จำกัด การขยายไฟล์ที่มีไวยากรณ์ของ JSX

คุณสามารถใช้กฎนี้ต่อไป แต่ฉันชอบที่จะใช้ส่วนขยาย js สำหรับไฟล์ทั้งหมดดังนั้นฉันจะปิดการใช้งานกฎนี้:

{
  "ขยาย": "airbnb",
  "env": {
    "es6": จริง
    "เบราว์เซอร์": จริง
    "node": จริง
  }
  "กฎ": {
    "react / jsx-filename-extension": 0
  }
}

การเปิดใช้งาน HMR

การเปิดใช้งานการเปลี่ยนโมดูลร้อนนั้นง่ายพอ ๆ กับการเพิ่มบล็อกของรหัส:

/ **
 * index.js
 * /
นำเข้าปฏิกิริยาจาก 'ปฏิกิริยา';
นำเข้า {render} จาก 'react-dom';
if (module.hot) {
  module.hot.accept ();
}
const MainApp = () => (
  

สวัสดีตอบโต้!

);
// แสดงแอพ
แสดงผล (, document.getElementById ('แอป'));

เคล็ดลับและแนวทางปฏิบัติที่ดีที่สุด

ก่อนที่เราจะทำการสอนต่อไปเราจะพูดถึงรายการเคล็ดลับและแนวทางปฏิบัติที่ดีที่สุดที่ฉันได้เรียนรู้จากประสบการณ์การทำงานกับ React และจากการอ่านและค้นหาในเว็บ ระลึกถึงสิ่งเหล่านั้นเมื่อคุณสร้างส่วนประกอบ React

การนำเข้าที่อ้างอิงกับการนำเข้าในท้องถิ่น

แยกการพึ่งพาการนำเข้าจากการนำเข้าภายในด้วยบรรทัดใหม่ การนำเข้าการพึ่งพาควรมาก่อน

นำเข้า React {Component} จาก 'react';
นำเข้าโมดูลประโยชน์จาก 'โมดูลที่เป็นประโยชน์';
นำเข้า myLocalModule จาก './my-local-module';

ส่วนประกอบการทำงานที่ไร้สัญชาติ

หากส่วนประกอบนั้นเป็นองค์ประกอบของการเรนเดอร์อย่างเดียวหรือไม่จำเป็นต้องใช้ State Object ให้ใช้ฟังก์ชัน JavaScript ธรรมดาแทนคลาส สิ่งนี้เรียกว่าคอมโพเนนต์การทำงานแบบไร้รัฐ

ดังนั้นแทนที่จะทำสิ่งนี้:

นำเข้า React {Component} จาก 'react';
คลาส MyComponent ขยายคอมโพเนนต์ {
  แสดงผล () {
    ผลตอบแทน (
      
Hello!     );   } }
ส่งออกเริ่มต้น MyComponent;

ทำเช่นนี้:

นำเข้าปฏิกิริยาจาก 'ปฏิกิริยา';
const MyComponent = () => 
Hello!
;
ส่งออกเริ่มต้น MyComponent;

ดูว่ามีการลบความยุ่งเหยิงเท่าใด คุณสามารถทำให้มันง่ายขึ้นได้ด้วยการส่งออกฟังก์ชัน:

นำเข้าปฏิกิริยาจาก 'ปฏิกิริยา';
ส่งออกค่าเริ่มต้น () => 
Hello!
;

อย่างไรก็ตามฉันไม่ชอบการทำเช่นนี้เพราะจะทำให้การแก้ไขข้อบกพร่องยากขึ้น หากคุณตรวจสอบ React Dev Tools คุณจะเห็นว่าชื่อส่วนประกอบเป็น "ไม่ทราบ" เนื่องจากฟังก์ชั่นนั้นไม่ระบุชื่อ

องค์ประกอบการใช้งานที่ไม่ระบุชื่อ

วิธีที่ดีกว่าคือการใช้ฟังก์ชั่นปกติที่มีชื่อแทนฟังก์ชั่นที่ไม่ระบุชื่อ:

นำเข้าปฏิกิริยาจาก 'ปฏิกิริยา';
ฟังก์ชันเริ่มต้นส่งออก MyComponent () {
  ส่งคืน 
Hello!
; }
องค์ประกอบการทำงานที่มีชื่อ

เริ่มต้นด้วยส่วนประกอบที่นำเสนอ

องค์ประกอบของงานนำเสนอนั้นง่ายต่อการกำหนดง่ายต่อการเข้าใจและสามารถนำไปใช้ซ้ำได้เนื่องจากเป็นอิสระจากส่วนที่เหลือของแอปพลิเคชัน

หากคุณแยกแอปพลิเคชันของคุณลงในชุดของส่วนประกอบที่นำเสนอคุณสามารถใส่พวกมันทั้งหมดไว้ในหน้าเดียวและปรับแต่งการออกแบบและรูปแบบต่าง ๆ เพื่อให้ได้รูปลักษณ์ที่เป็นหนึ่งเดียวตลอดทั้งแอปพลิเคชัน

สร้างองค์ประกอบของคุณเป็นองค์ประกอบการนำเสนอและเพิ่มสถานะเมื่อคุณต้องการเท่านั้นซึ่งจะนำเราไปสู่เคล็ดลับต่อไป

ลดการใช้งานของรัฐให้น้อยที่สุด

ใช้สถานะเท่าที่จำเป็นในองค์ประกอบของคุณและให้แน่ใจว่าพวกเขาใช้สถานะสำหรับ UI มากกว่าข้อมูลในคำอื่น ๆ ถ้าคุณไม่ได้ใช้มันในการแสดงผล () แล้วมันไม่ควรจะอยู่ในสถานะ จำไว้ว่าคุณควรใช้ setState หากคุณต้องการแสดงองค์ประกอบของคุณอีกครั้ง

ให้เราบอกว่าเรามีองค์ประกอบที่ประกอบด้วยปุ่มเดียว ปุ่มนี้อาจถูกคลิกเพียงครั้งเดียวและเมื่อมีการคลิกข้อความจะถูกบันทึกลงในคอนโซล:

นำเข้า React {Component} จาก 'react';

คลาส MyComponent ขยายคอมโพเนนต์ {
  state = {
    clickedOnce: false
  };
  handleClick = () => {
    ถ้า (! this.state.clickedOnce) {
      console.log ( 'คลิก');
    }
    this.setState ({
      clickedOnce: จริง
    });
  }
  componentDidUpdate () {
    console.log ( 'ปรับ!');
  }
  แสดงผล () {
    ผลตอบแทน (
      
                    );   } }
ส่งออกเริ่มต้น MyComponent;

นี่เป็นตัวอย่างของการใช้งานที่ไม่ดีโดยใช้สถานะเพื่อตั้งค่าสถานะ clickedOnce ซึ่งระบุว่าสามารถคลิกปุ่มได้อีกครั้ง ทุกครั้งที่มีการคลิกปุ่มส่วนประกอบจะแสดงผลซ้ำแม้ว่าจะไม่จำเป็นก็ตาม

แอปพลิเคชันแสดงผลอีกครั้งเมื่อคลิกปุ่ม

นี่จะดีกว่า:

นำเข้า React {Component} จาก 'react';

คลาส MyComponent ขยายคอมโพเนนต์ {
  clickedOnce = false;
  
  handleClick = () => {
    ถ้า (! this.clickedOnce) {
      console.log ( 'คลิก');
    }
    this.clickedOnce = true;
  }
  componentDidUpdate () {
    console.log ( 'ปรับ!');
  }
  แสดงผล () {
    ผลตอบแทน (
      
                    );   } }
ส่งออกเริ่มต้น MyComponent;

การใช้งานนี้ใช้คุณสมบัติคลาสแทนคีย์สถานะเนื่องจากค่าสถานะ clickedOnce ไม่ได้แสดงสถานะ UI และด้วยเหตุนี้ไม่ควรอยู่ภายในสถานะคอมโพเนนต์ ด้วยการใช้งานใหม่นี้การคลิกปุ่มมากกว่าหนึ่งครั้งจะไม่ทำให้เกิดการอัปเดตอีกต่อไป

กำหนด propTypes และ defaultProps เสมอ

ส่วนประกอบทั้งหมดควรมี propTypes และ defaultProps ที่กำหนดไว้สูงที่สุดเท่าที่จะเป็นไปได้ภายในส่วนประกอบ พวกเขาทำหน้าที่เป็นเอกสารประกอบและควรจะเห็นได้ทันทีเมื่อนักพัฒนาคนอื่นอ่านไฟล์

ตั้งแต่ React v15.5, React.PropTypes ได้ย้ายไปอยู่ในแพ็คเกจอื่นดังนั้นให้เราติดตั้งแพ็กเกจนั้นเป็นการอ้างอิง:

$ npm ติดตั้ง - บันทึก prop-types

สำหรับส่วนประกอบการทำงานที่ไร้สัญชาติ:

ฟังก์ชั่นถูกยกขึ้นใน JavaScript ซึ่งหมายความว่าคุณสามารถใช้ฟังก์ชั่นก่อนการประกาศ:

นำเข้าปฏิกิริยาจาก 'ปฏิกิริยา';
นำเข้า PropTypes จาก 'prop-types';
MyComponent.propTypes = {
  ชื่อเรื่อง: PropTypes.string,
};
MyComponent.defaultProps = {
  ชื่อเรื่อง: 'เคาน์เตอร์ง่าย ๆ ',
};
ฟังก์ชันเริ่มต้นส่งออก MyComponent (อุปกรณ์ประกอบฉาก) {
  ส่งคืน 

{props.title}

; }

ESLint จะบ่นเกี่ยวกับการใช้ฟังก์ชั่นก่อนที่จะมีความหมาย แต่เพื่อประโยชน์ของเอกสารประกอบที่ดีกว่าให้เราปิดการใช้งานกฎ linting นี้สำหรับฟังก์ชั่นโดยการแก้ไขไฟล์. eslintrc:

{
  ...
  "กฎ": {
    "react / jsx-filename-extension": 0,
    "no-use-before-define": [
      "ความผิดพลาด"
      {
        "ฟังก์ชั่น": เท็จ
      }
    ]
  }
}

สำหรับส่วนประกอบพื้นฐาน:

ไม่เหมือนกับฟังก์ชั่นคลาสใน JavaScript จึงไม่ถูกยกขึ้นดังนั้นเราจึงไม่สามารถทำ MyComponent.propTypes = ... ก่อนกำหนดคลาสเอง แต่เราสามารถกำหนด propTypes และ defaultProps เป็นคุณสมบัติคลาสแบบสแตติก:

นำเข้า React {Component} จาก 'react';
นำเข้า PropTypes จาก 'prop-types';
คลาส MyComponent ขยายคอมโพเนนต์ {
  propTypes คงที่ = {
    ชื่อเรื่อง: PropTypes.string,
  };
  คง defaultProps = {
    ชื่อเรื่อง: 'เคาน์เตอร์ง่าย ๆ ',
  };
  แสดงผล () {
    ส่งคืน 

{this.props.title}

;   } }
ส่งออกเริ่มต้น MyComponent;

เริ่มต้นของรัฐ

สถานะสามารถเริ่มต้นได้ภายในตัวสร้างส่วนประกอบ:

คลาส MyComponent ขยายคอมโพเนนต์ {
  ตัวสร้าง (อุปกรณ์ประกอบฉาก) {
    ซุปเปอร์ (อุปกรณ์ประกอบฉาก);
    this.state = {
      นับ: 0,
    };
  }
}

วิธีที่ดีกว่าคือการเริ่มต้นสถานะเป็นคุณสมบัติคลาส:

คลาส MyComponent ขยายคอมโพเนนต์ {
  ตัวสร้าง (อุปกรณ์ประกอบฉาก) {
    ซุปเปอร์ (อุปกรณ์ประกอบฉาก);
  }
  state = {
    นับ: 0,
  };
}

สิ่งนี้ดูดีขึ้นสะอาดขึ้นอ่านได้มากขึ้นและยังมีส่วนร่วมในเอกสารประกอบของส่วนประกอบ วัตถุสถานะควรเริ่มต้นได้หลังจาก propTypes และ defaultProps:

นำเข้า React {Component} จาก 'react';
นำเข้า PropTypes จาก 'prop-types';
คลาส MyComponent ขยายคอมโพเนนต์ {
  // propTypes ต้องมาก่อน
  propTypes คงที่ = {
    ชื่อเรื่อง: PropTypes.string,
  };
  // defaultProps มาเป็นอันดับที่สอง
  คง defaultProps = {
    ชื่อเรื่อง: 'เคาน์เตอร์ง่าย ๆ ',
  };
  // คอนสตรัคเตอร์มาที่นี่
  ตัวสร้าง () {
    ...
  }
  // จากนั้นรัฐก็มา
  state = {
    นับ: 0,
  };
}

ผ่านฟังก์ชั่นเพื่อ setState

เอกสารตอบโต้ทำให้หมดกำลังใจโดยอาศัยค่า this.state และ this.props สำหรับการคำนวณสถานะต่อไปเนื่องจาก React จะอัพเดตแบบอะซิงโครนัส นั่นหมายความว่าสถานะอาจไม่เปลี่ยนแปลงทันทีหลังจากเรียก setState ()

คลาส MyComponent ขยายคอมโพเนนต์ {
  state = {
    นับ: 10
  }
  onClick = () => {
    console.log (this.state.count); // 10
    
    // จำนวนจะไม่เปลี่ยนแปลงทันที
    this.setState ({นับ: this.state.count + this.props.step});
    
    console.log (this.state.count); // ยัง 10
  }
}

ในขณะที่ใช้งานได้กับสถานการณ์อย่างง่ายและสถานะจะยังคงได้รับการปรับปรุงอย่างถูกต้อง แต่อาจนำไปสู่พฤติกรรมที่ไม่คาดคิดในสถานการณ์ที่ซับซ้อน

พิจารณาสถานการณ์นี้คุณมีองค์ประกอบที่ทำให้ปุ่มเดียว เมื่อคลิกปุ่มนี้จะมีการเรียกใช้เมธอด handleClick:

คลาส MyComponent ขยายคอมโพเนนต์ {
  คง defaultProps = {
    ขั้นตอน: 5,
  }
  propTypes คงที่ = {
    ขั้นตอน: PropTypes.number
  }
  
  state = {
    นับ: 10
  }
  
  handleClick = () => {
    this.doSomething ();
    this.doSomethingElse ();
  }
  doSomething = () => {
    this.setState ({นับ: this.state.count + this.props.step});
  }
  doSomethingElse = () => {
    this.setState ({นับ: this.state.count - 1});
  }
  แสดงผล () {
    ผลตอบแทน (
      
        

จำนวนปัจจุบันคือ: {this.state.count}

                    );   } }

ปุ่มเรียก handleClick () เมื่อคลิกซึ่งจะเรียก doSomething () จากนั้น doSomethingElse () ฟังก์ชั่นทั้งสองจะปรับเปลี่ยนค่าการนับภายในรัฐ

ตามหลักเหตุผล 10 + 5 เท่ากับ 15 แล้วลบ 1 และผลลัพธ์ควรเป็น 14 จริงไหม ในกรณีนี้มันไม่ใช่ - ค่าของการนับหลังจากคลิกครั้งแรกคือ 9 ไม่ใช่ 14 สิ่งนี้เกิดขึ้นเพราะค่าของ this.state.count ยังคงเป็น 10 เมื่อ doSomethingElse () ถูกเรียกไม่ใช่ 15

ในการแก้ไขปัญหานี้คุณสามารถใช้รูปแบบที่สองของ setState () ที่รับฟังก์ชั่นแทนที่จะเป็นวัตถุ ฟังก์ชั่นนั้นจะได้รับสถานะก่อนหน้านี้เป็นอาร์กิวเมนต์แรกและอุปกรณ์ประกอบฉาก ณ เวลาที่มีการปรับปรุงใช้เป็นอาร์กิวเมนต์ที่สอง:

this.setState ((prevState อุปกรณ์ประกอบฉาก) => ({
  นับ: prevState.count + props.step
}))

เราสามารถใช้แบบฟอร์มนี้เพื่อแก้ไขตัวอย่างของเรา:

คลาส MyComponent ขยายคอมโพเนนต์ {
  ...
  handleClick = () => {
    this.doSomething ();
    this.doSomethingElse ();
  }
  doSomething = () => {
    this.setState ((prevState อุปกรณ์ประกอบฉาก) => ({
      นับ: prevState.count + props.step
    }));
  }
  doSomethingElse = () => {
    this.setState (prevState => ({
      นับ: prevState.count - 1
    }));
  }
  ...
}

ด้วยการใช้งานนี้การนับจะมีการอัปเดตอย่างถูกต้องตั้งแต่ 10 ถึง 14 ถึง 18 เป็นต้น คณิตศาสตร์อย่างง่ายทำให้รู้สึกอีกครั้ง!

ใช้ฟังก์ชั่นลูกศรเป็นคุณสมบัติของคลาส

คำหลักนี้สร้างความสับสนให้กับนักพัฒนา JavaScript เสมอและพฤติกรรมนั้นไม่ได้ทำให้สับสนในส่วนประกอบของปฏิกิริยา คุณรู้หรือไม่ว่าคำหลักนี้มีการเปลี่ยนแปลงอย่างไรในส่วนประกอบ React ลองพิจารณาตัวอย่างต่อไปนี้:

นำเข้า React {Component} จาก 'react';
คลาส MyComponent ขยายคอมโพเนนต์ {
  state = {
    นับ: 0,
  };
  เมื่อคลิก() {
    console.log (this.state);
  }
  แสดงผล () {
    ผลตอบแทน (
      
        

จำนวนคือ: {this.state.count}

                    );   } }
ส่งออกเริ่มต้น MyComponent;

การคลิกปุ่มจะทำให้เกิดข้อผิดพลาด:

Uncaught TypeError: ไม่สามารถอ่านคุณสมบัติ ‘state’ ของ undefined

นี่เป็นเพราะ onClick เป็นวิธีการเรียนไม่ได้ถูกผูกไว้โดยค่าเริ่มต้น มีสองสามวิธีในการแก้ไขปัญหานี้ (เล่นสำนวนเจตนาเอาไว้?)

วิธีหนึ่งคือการผูกฟังก์ชั่นกับบริบทที่ถูกต้องในขณะที่คุณผ่านเข้าไปในฟังก์ชั่นการแสดงผล ():

หรือคุณสามารถหลีกเลี่ยงการเปลี่ยนบริบทโดยใช้ฟังก์ชันลูกศรในการแสดงผล ():

อย่างไรก็ตามทั้งสองวิธีมีค่าใช้จ่ายประสิทธิภาพเล็กน้อยเนื่องจากฟังก์ชันจะถูกจัดสรรใหม่ในการแสดงผลแต่ละครั้ง เพื่อหลีกเลี่ยงค่าใช้จ่ายประสิทธิภาพเล็กน้อยคุณสามารถผูกฟังก์ชั่นภายในตัวสร้างได้:

นำเข้า React {Component} จาก 'react';
คลาส MyComponent ขยายคอมโพเนนต์ {
  ตัวสร้าง (อุปกรณ์ประกอบฉาก) {
    ซุปเปอร์ (อุปกรณ์ประกอบฉาก);
    this.onClick = this.onClick.bind (นี่);
  }
  ...
  แสดงผล () {
    ...
    
    ...
  }
}
ส่งออกเริ่มต้น MyComponent;

เทคนิคนี้ดีกว่า แต่คุณสามารถถูกพาตัวไปและจบลงด้วยสิ่งที่มีลักษณะเช่นนี้:

ตัวสร้าง (อุปกรณ์ประกอบฉาก) {
  // นี่แย่มากแย่จริงๆ
  this.onClick = this.onClick.bind (นี่);
  this.onChange = this.onChange.bind (นี่);
  this.onSubmit = this.onSubmit.bind (นี่);
  this.increaseCount = this.increaseCount.bind (นี่);
  this.decreaseCount = this.decreaseCount.bind (นี่);
  this.resetCount = this.resetCount.bind (นี่);
  ...
}

เนื่องจากเราใช้ Babel และมีการสนับสนุนคุณสมบัติคลาสวิธีที่ดีกว่าคือการใช้ฟังก์ชั่นลูกศรเมื่อกำหนดวิธีการเรียน:

คลาส MyComponent ขยายคอมโพเนนต์ {
  ...
  onClick = () => {
    // 'นี่' ถูกเก็บรักษาไว้
    console.log (this.state);
  }
  แสดงผล () {
    ผลตอบแทน (
      
        

{} this.state.count                     );   } }

ทำลายวัตถุอุปกรณ์ประกอบฉาก

เมื่อส่วนประกอบมีอุปกรณ์ประกอบฉากมากมายให้ทำลายวัตถุอุปกรณ์ประกอบฉากที่วางคุณสมบัติแต่ละรายการในสายของตนเอง

สำหรับส่วนประกอบการทำงานที่ไร้สัญชาติ:

ฟังก์ชันเริ่มต้นส่งออก MyComponent ({
  ชื่อจริง,
  นามสกุล,
  ที่อยู่อีเมล,
  คำอธิบาย
  onChange,
  onSubmit,
}) {
  ผลตอบแทน (
    
      

{} firstName       ...        ); }

อาร์กิวเมนต์เริ่มต้นไม่ใช่ข้อแก้ตัวในการปล่อย defaultProps ตามที่กล่าวไว้ก่อนหน้านี้คุณควรกำหนด propTypes และ defaultProps

สำหรับส่วนประกอบพื้นฐาน:

คลาส MyComponent ขยายคอมโพเนนต์ {
  ...
  แสดงผล () {
    const {
      ชื่อจริง,
      นามสกุล,
      ที่อยู่อีเมล,
      คำอธิบาย
      onChange,
      onSubmit,
    } = this.props;
    ผลตอบแทน (
      
        

{} firstName         ...            );   } }

นี่คือตัวทำความสะอาดทำให้ง่ายต่อการเรียงลำดับคุณสมบัติใหม่และทำให้ง่ายต่อการเพิ่ม / ลบคุณสมบัติไปยัง / จากรายการในขณะที่สร้างส่วนต่างที่สามารถอ่านได้สำหรับ Git พิจารณาสิ่งต่อไปนี้:

การกระจายจะอ่านได้ง่ายขึ้นเมื่อคุณสมบัติแต่ละรายการอยู่ในบรรทัดใหม่

ทางด้านขวามือคุณสามารถบอกได้อย่างง่ายดายว่ามีการเพิ่มคุณสมบัติอย่างไรทางด้านซ้ายมือคุณรู้เพียงว่ามีบางอย่างเปลี่ยนไปบนบรรทัดนั้นและคุณต้องดูอย่างระมัดระวังเพื่อให้เข้าใจว่าส่วนใดของเส้นตรงนั้น การเปลี่ยนแปลง

การแสดงผลตามเงื่อนไข

เมื่อคุณต้องการแสดงผลหนึ่งในสององค์ประกอบหรือบล็อกของรหัส JSX ตามเงื่อนไขให้ใช้นิพจน์ประกอบไปด้วย:

IsLoggedIn
  ? 
ยินดีต้อนรับ {username}!
  :

หากรหัสประกอบด้วยมากกว่าหนึ่งบรรทัดให้ใช้วงเล็บ:

isLoggedIn? (
  
    ยินดีต้อนรับ {usename}!    ): (   

หากคุณต้องการแสดงผลองค์ประกอบเดียวหรือบล็อกของรหัส JSX ตามเงื่อนไขให้ใช้การประเมินการลัดวงจรแทน:

isComplete && 
เสร็จแล้ว!

สำหรับมากกว่าหนึ่งบรรทัดให้ใช้วงเล็บ:

isComplete && ((
  
    คุณทำเสร็จแล้ว!    )

คุณสมบัติที่สำคัญ

มันเป็นรูปแบบทั่วไปในการใช้ Array.prototype.map และวิธีการเรียงลำดับที่คล้ายกันภายในฟังก์ชั่น render () และมันง่ายที่จะลืมเกี่ยวกับคุณลักษณะที่สำคัญ การไกล่เกลี่ยนั้นยากพออย่าทำให้ยากขึ้น อย่าลืมวางกุญแจไว้ในที่ที่เป็นของมัน (เล่นสำนวนตั้งใจอีกครั้งเอามันมา?)

แสดงผล () {
  ผลตอบแทน (
    
    {       {         items.map (รายการ => (           
  •             {item.name}                    ))        }        ); }

เมื่อคุณใช้ map (), filter () หรือวิธีการ array ที่คล้ายกันพารามิเตอร์ที่สองสำหรับการโทรกลับคือดัชนีของรายการ โดยทั่วไปควรใช้ดัชนีนี้เป็นคีย์ React ใช้คุณลักษณะที่สำคัญในการระบุรายการที่มีการเปลี่ยนแปลงได้รับการเพิ่มหรือถูกลบออกและค่าคีย์ควรมีเสถียรภาพและควรระบุแต่ละรายการโดยไม่ซ้ำกัน

ในกรณีที่มีการเรียงลำดับอาร์เรย์หรือองค์ประกอบถูกเพิ่มไปยังจุดเริ่มต้นของอาร์เรย์ดัชนีจะมีการเปลี่ยนแปลงแม้ว่าองค์ประกอบที่เป็นตัวแทนของดัชนีนั้นอาจจะเหมือนกัน ซึ่งส่งผลในการแสดงผลที่ไม่จำเป็นและในบางกรณีผลลัพธ์ในการแสดงข้อมูลที่ไม่ถูกต้อง

ใช้ UUID หรือ ShortID เพื่อสร้าง id ที่ไม่ซ้ำกันสำหรับแต่ละรายการเมื่อมันถูกสร้างขึ้นครั้งแรกและใช้เป็นค่าคีย์

ทำให้สถานะเป็นปกติ

พยายามทำให้วัตถุสถานะเป็นปกติและทำให้มันเรียบเท่าที่จะทำได้ ข้อมูลการซ้อนในสถานะหมายความว่าจำเป็นต้องใช้ตรรกะที่ซับซ้อนกว่าเพื่ออัพเดต ลองนึกภาพว่ามันน่าเกลียดแค่ไหนในการอัพเดทสนามที่ซ้อนกันอย่างลึกล้ำ - รออย่าจินตนาการที่นี่:

// วัตถุสถานะ
state = {
  ...
  โพสต์: [
    ... ,
    {
      เมตา: {
        id: 12
        ผู้แต่ง: '... ',
        สาธารณะ: เท็จ
        ...
      }
      ...
    }
    ...
  ]
  ...
};
// เพื่ออัปเดต 'สาธารณะ' เป็น 'จริง'
this.setState ({
  ... this.state,
  โพสต์: [
    ... this.state.posts.slice (0, ดัชนี)
    {
      ... this.state.posts [ดัชนี]
      เมตา: {
        ... this.state.posts [ดัชนี] .meta,
        สาธารณะ: จริง
      }
    }
    ... this.state.posts.slice (ดัชนี + 1)
  ]
});

รหัสนี้ไม่เพียง แต่น่าเกลียดเท่านั้น แต่ยังสามารถบังคับให้ส่วนประกอบที่ไม่เกี่ยวข้องแสดงผลอีกครั้งแม้ว่าข้อมูลที่แสดงจะไม่ได้เปลี่ยนไปจริง นี่เป็นเพราะเราได้อัปเดตบรรพบุรุษทั้งหมดในแผนผังสถานะด้วยการอ้างอิงวัตถุใหม่

การอัปเดตฟิลด์เดียวกันจะง่ายขึ้นหากเราปรับโครงสร้างแผนผังสถานะอีกครั้ง:

state = {
  โพสต์: [
    10
    11
    12
  ]
  เมตา: {
    10: {
      id: 10
      ผู้แต่ง: 'author-a',
      สาธารณะ: เท็จ
    }
    11: {
      id: 11,
      ผู้แต่ง: 'author-b',
      สาธารณะ: เท็จ
    }
    12: {
      id: 12
      ผู้แต่ง: 'author-c',
      สาธารณะ: เท็จ
    }
  }
}
this.setState ({
  เมตา: {
    ... this.state.meta,
    [id]: {
      ... this.state.meta [ID]
      สาธารณะ: จริง
    }
  }
})

ใช้ชื่อคลาส

หากคุณเคยอยู่ในสถานการณ์ที่จำเป็นต้องใช้ชื่อคลาสที่มีเงื่อนไขคุณอาจเขียนบางสิ่งที่มีลักษณะดังนี้:

  ...

สิ่งนี้จะน่าเกลียดถ้าคุณมีชื่อคลาสที่มีเงื่อนไขหลายเงื่อนไข แทนที่จะใช้ไตรภาคให้ใช้แพ็คเกจชื่อคลาส:

นำเข้าชื่อคลาสจาก 'ชื่อคลาส';
const คลาส = classnames ('แท็บ', {'is-active': isActive});
  ...

หนึ่งองค์ประกอบต่อไฟล์

นี่ไม่ใช่กฎที่ยาก แต่ฉันต้องการเก็บแต่ละองค์ประกอบไว้ในไฟล์เดียวและส่งออกองค์ประกอบเริ่มต้นนั้น ฉันไม่มีเหตุผลที่เฉพาะเจาะจงสำหรับเรื่องนี้ แต่ฉันแค่พบว่ามันสะอาดและเป็นระเบียบมากขึ้น - สูงห้าถ้าคุณทำเช่นนั้น!

ข้อสรุป

ไม่มีวิธีการที่ถูกต้องในการพัฒนาส่วนประกอบ React เราได้ผ่านแนวปฏิบัติและรูปแบบที่ดีที่สุดสองสามข้อที่จะช่วยให้คุณพัฒนาส่วนประกอบที่สามารถนำมาใช้ซ้ำได้และบำรุงรักษาได้และฉันอยากรู้ว่าคุณต้องการรูปแบบและแนวทางปฏิบัติแบบใดและทำไม

ในส่วนถัดไปของชุดนี้เราจะสร้างแอปพลิเคชั่นที่ต้องทำที่เรียบง่ายและใช้แนวทางปฏิบัติและรูปแบบที่ดีที่สุดเหล่านี้

บทความนี้มีประโยชน์ไหม โปรดคลิกที่ปุ่ม Clap ด้านล่างหรือติดตามฉันได้มากกว่านี้

ขอบคุณที่อ่าน! หากคุณมีข้อเสนอแนะใด ๆ แสดงความคิดเห็นด้านล่าง

ไปที่ส่วนที่ 7-b: สร้างแอพ ToDo ง่ายๆ (เร็ว ๆ นี้)