React中文文件閱讀總結——快速入門

宮商角徵羽發表於2018-05-10

快速入門

點選進入——React中文文件


JSX及元素渲染

  1. React 是一個 JavaScript 庫

  2. const element = <h1>Hello, world!</h1>; 考慮一下這個變數的宣告,它既不是字串也不是HTML,這就是 JSX ,它是 JavaScrip 的一種擴充套件語法。我們推薦在 React 中使用這種語法來描述 UI 資訊,它具有 JavaScrip 的全部能力,可以生成React “元素”。

  3. 比起 HTML,JSX 更接近於 JavaScript,所以 React DOM 使用駝峰(camelCase)屬性命名約定,而不是HTML屬性名稱。 例如,class 在JSX中變為classNametabindex 變為 tabIndex

  4. 元素(Elements)是 React 應用中最小的構建部件,它是構成組建的“材料”,一個元素用於描述你在將在螢幕上看到的內容,例如:const element = <h1>Hello, world</h1>;

  5. React 元素是 不可突變(immutable) 的,一旦你建立了一個元素, 就不能再修改其子元素或任何屬性。一個元素就像電影裡的一幀: 它表示在某一特定時間點的 UI 。更新 UI 的唯一方法是建立一個新的元素, 並將其傳入ReactDOM.render() 方法。但實際上,大多數 React 應用只會呼叫 ReactDOM.render() 一次。更新UI更多的是通過與 狀態(state)生命週期 掛鉤來實現的。

元件(Components) 和 屬性(Props)

  1. 元件名稱總是以大寫字母開始

  2. 元件必須返回一個單獨的根元素。

  3. function sum(a, b) { return a + b; },這種函式稱為 “ 純函式 ” ,因為它們不會試圖改變它們的輸入,並且 對於同樣的輸入,始終可以得到相同的結果 。 反之, 以下是非純函式, 因為它改變了自身的輸入值: function withdraw(account, amount) { account.total -= amount; }

  4. 所有 React 元件都必須是 純函式,並禁止修改其自身 props 。

狀態(State) 和 生命週期

  1. this.props 由 React 本身設定, 而 this.state 具有特殊的含義,但如果需要儲存一些不用於視覺輸出的內容,則可以手動向類中新增額外的欄位。 如果在 render() 方法中沒有被引用, 它不應該出現在 state

  2. 關於 setState() 有三件事是你應該知道的:

  • 不要直接修改 state(狀態)

    例如,這樣將不會重新渲染一個元件:this.state.comment = 'Hello';

    正確的做法是用 setState() 來修改 statethis.setState({comment: 'Hello'});

  • state(狀態) 更新可能是非同步的

    React 為了優化效能,有可能會將多個 setState() 呼叫合併為一次更新。因為 this.propsthis.state 可能是非同步更新的,你不能依賴他們的值計算下一個state(狀態)。

    例如, 以下程式碼可能導致 counter(計數器)更新失敗:

    // 錯誤
    this.setState({
      counter: this.state.counter + this.props.increment,
    });
    複製程式碼

    要彌補這個問題,使用另一種 setState() 的形式,它 接受一個函式而不是一個物件 。這個函式將接收 前一個狀態 作為 第一個引數 ,應用 更新時的 props 作為 第二個引數

    // 正確
    this.setState((prevState, props) => ({
      counter: prevState.counter + props.increment
    }));
    複製程式碼
  • state(狀態)更新會被合併

    當你呼叫 setState() , React 將合併你提供的物件到當前的狀態中。

  • 資料向下流動

    如果把元件樹想像為 props(屬性) 的瀑布,所有元件的 state(狀態) 就如同一個額外的水源匯入主流,且只能隨著主流的方向向下流動。

    任何 state(狀態) 始終由某個特定元件所有,並且從該 state(狀態) 匯出的任何資料 或 UI 只能影響樹中 “下方” 的元件。

處理事件

  1. 通過 React 元素處理事件跟在 DOM 元素上處理事件非常相似。但是有一些語法上的區別:
  • React 事件使用駝峰命名,而不是全部小寫。

  • 通過 JSX , 你傳遞一個函式作為事件處理程式,而不是一個字串。

  • 在 React 中你不能通過返回 false 來阻止預設行為。必須明確呼叫 preventDefault 。例如,對於純 HTML ,要阻止連結開啟一個新頁面的預設行為,可以這樣寫:

    <a href="#" onclick="console.log('The link was clicked.'); return false">
      Click me
    </a>
    複製程式碼

    在 React 中, 應該這麼寫:

    function ActionLink() {
      function handleClick(e) {
        e.preventDefault();
        console.log('The link was clicked.');
      }
    
      return (
        <a href="#" onClick={handleClick}>
          Click me
        </a>
      );
    }
    複製程式碼

條件渲染

  1. 在 React 中,你可以建立不同的元件封裝你所需要的行為。然後,只渲染它們之中的一些,取決於你的應用的狀態。 React 中的條件渲染就和在 JavaScript 中的條件語句一樣 。使用 JavaScript 操作符如 if 或者條件操作符來建立渲染當前狀態的元素,並且讓 React 更新匹配的 UI 。

    雖然宣告一個變數並使用一個 if 語句是一個有條件地渲染元件的好方法,有時你可能想要使用一個更簡短的語法。在 JSX 中有幾種內聯條件的方法,如下所述。

    • 使用邏輯 && 操作符的內聯 if 用法

      例如當陣列arr不為空時渲染元件 <ShowMessages> ,可以寫成

      { 
          arr.length>0 &&
          <ShowMessages>
      }
      複製程式碼

      它可以正常執行,因為在 JavaScript 中, true && expression 總是會評估為 expression ,而 false && expression 總是執行為 false 。 因此,如果條件為 true ,則 && 後面的元素將顯示在輸出中。 如果是 false,React 將會忽略並跳過它

    • 使用條件操作符的內聯 If-Else

      另一個用於條件渲染元素的內聯方法是使用 JavaScript 的條件操作符 If-Else 或者是三目運算子 condition ? true : false

    還要記住,無論何時何地,當條件變得太複雜時,可能是提取元件的好時機

  2. 防止元件渲染

    在極少數情況下,您可能希望元件隱藏自身,即使它是由另一個元件渲染的。為此,返回 null 而不使其渲染輸出

    例如在如下程式碼中:

    //方法一:
    function WarningBanner(props) {
      if (!props.warn) {
        return null;
      }
      return (
        <div className="warning">
          Warning!
        </div>
      );
    }
    
    class Page extends React.Component {
      constructor(props) {
        super(props);
        this.state = {showWarning: true}
        this.handleToggleClick = this.handleToggleClick.bind(this);
      }
    
      handleToggleClick() {
        this.setState(prevState => ({
          showWarning: !prevState.showWarning
        }));
      }
      
      render() {
        return (
          <div>
            <WarningBanner warn={this.state.showWarning} />
            <button onClick={this.handleToggleClick}>
              {this.state.showWarning ? 'Hide' : 'Show'}
            </button>
          </div>
        );
      }
    }
    
    ReactDOM.render(
      <Page />,
      document.getElementById('root')
    );
    複製程式碼

    Hide按鈕可以控制 Warning div 的顯示隱藏。 同樣,以下程式碼也能達到相同效果:

    //方法二:
    class Page extends React.Component {
      constructor(props) {
        super(props);
        this.state = {showWarning: true}
        this.handleToggleClick = this.handleToggleClick.bind(this);
      }
    
      handleToggleClick() {
        this.setState(prevState => ({
          showWarning: !prevState.showWarning
        }));
      }
      
      render() {
        return (
          <div>
            <div className="warning" style={{display:this.state.showWarning?'':'none'}}>
              Warning!
            </div>
            <button onClick={this.handleToggleClick}>
              {this.state.showWarning ? 'Hide' : 'Show'}
            </button>
          </div>
        );
      }
    }
    
    ReactDOM.render(
      <Page />,
      document.getElementById('root')
    );
    複製程式碼

    這裡沒有把 Warning div 當做元件抽離出來,雖然也能達到相同的效果,但是使用 display 只是控制了 Warning div 的顯示隱藏,不論如何,Warning div 其實都已經在頁面載入了,消耗了資源;而第一種方法返回 null ,卻是完完全全的控制了 Warning div 的載入,效能上更勝一籌。

    PS:從元件的 render 方法返回 null 不會影響元件生命週期方法的觸發。 例如, componentWillUpdatecomponentDidUpdate 仍將被呼叫。

列表(Lists) 和 鍵(Keys)

  1. 首先,先來看一段程式碼:

    const numbers = [1, 2, 3, 4, 5];
    const listItems = numbers.map((numbers) =>
      <li>{numbers}</li>
    );
    
    ReactDOM.render(
      <ul>{listItems}</ul>,
      document.getElementById('root')
    );
    複製程式碼

    這段程式碼顯示從 1 到 5 的數字列表。

    當執行上述程式碼時,雖然會正確顯示出列表,但是會收到一個警告:a key should be provided for list items(應該為列表元素提供一個鍵)。當建立元素列表時,“key” 是一個你需要包含的特殊字串屬性。 鍵(Keys) 幫助 React 標識哪個項被修改、新增或者移除了 。陣列中的 每一個元素 都應該有一個 唯一不變 的鍵(Keys)來標識。挑選 key 最好的方式是使用一個在它的同輩元素中不重複的標識字串。多數情況你可以使用資料中的 ID 作為 keys;當要渲染的列表項中沒有穩定的 IDs 時,你可以使用資料項的索引值作為 key 的最後選擇,例如:

    const numbers = [1, 2, 3, 4, 5];
    const listItems = numbers.map((numbers,index) =>
      <li key={index}>{numbers}</li>
    );
    
    ReactDOM.render(
      <ul>{listItems}</ul>,
      document.getElementById('root')
    );
    複製程式碼
  2. 使用 keys 提取元件 keys 只在陣列的上下文中存在意義。例如,如果你提取 一個 ListItem 元件,應該把 key 放置在陣列處理的 <ListItem /> 元素中,不能放在 ListItem 元件自身中的 <li> 根元素上。

    例如:

    function ListItem(props) {
      const value = props.value;
      return (
        // 錯誤!不需要在這裡指定 key:
        <li key={value.toString()}>
          {value}
        </li>
      );
    }
    
    function NumberList(props) {
      const numbers = props.numbers;
      const listItems = numbers.map((number) =>
        // 錯誤!key 應該在這裡指定:
        <ListItem value={number} />
      );
      return (
        <ul>
          {listItems}
        </ul>
      );
    }
    
    const numbers = [1, 2, 3, 4, 5];
    ReactDOM.render(
      <NumberList numbers={numbers} />,
      document.getElementById('root')
    );
    複製程式碼

    一個好的經驗準則是:元素中呼叫 map() 需要 keys

  3. keys同輩元素中必須是唯一

    在陣列中使用的 keys 必須在它們的同輩之間唯一。然而它們並不需要全域性唯一。我們可以在操作兩個不同陣列的時候使用相同的 keys。

表單(Forms)

  1. 受控元件(Controlled Components)

    在 HTML 中,表單元素如 <input><textarea><select> 表單元素通常保持自己的狀態,並根據使用者輸入進行更新。而在 React 中,可變狀態一般儲存在元件的 state(狀態) 屬性中,並且只能通過 setState() 更新。

    我們可以通過使 React 的 state 成為 “單一資料來源原則” 來結合這兩個形式。然後渲染表單的 React 元件也可以控制在使用者輸入之後的行為。這種形式,其 值由 React 控制的輸入表單元素 稱為“ 受控元件 ”。

    例如,如果我們想在提交時記錄名稱,我們可以將表單寫為受控元件:

    class NameForm extends React.Component {
      constructor(props) {
        super(props);
        this.state = {value: ''};
      }
    
      handleChange(event) {
        this.setState({value: event.target.value});
      }
    
      handleSubmit(event) {
        alert('A name was submitted: ' + this.state.value);
        event.preventDefault();
      }
    
      render() {
        return (
          <form onSubmit={this.handleSubmit.bind(this)}>
            <label>
              Name:
              <input type="text" value={this.state.value} onChange={this.handleChange.bind(this)} />
            </label>
            <input type="submit" value="Submit" />
          </form>
        );
      }
    }
    
    ReactDOM.render(
      <NameForm />,
      document.getElementById('root')
    );
    複製程式碼

    設定表單元素的value屬性之後,其顯示值將由 this.state.value 決定,以滿足React狀態的同一資料理念。每次鍵盤敲擊之後會執行 handleChange 方法以更新React狀態,顯示值也將隨著使用者的輸入改變。

    由於 value 屬性設定在我們的表單元素上,顯示的值總是 this.state.value,以滿足 state 狀態的同一資料理念。由於 handleChange 在每次敲擊鍵盤時執行,以更新 React state(狀態),顯示的值將更新為使用者的輸入。

    對於受控元件來說,每一次 state(狀態) 變化都會伴有相關聯的處理函式。這使得可以直接修改或驗證使用者的輸入。

  2. 處理多個輸入元素

    當您需要處理多個受控的 input 元素時,您可以為每個元素新增一個 name 屬性,並且讓處理函式根據 event.target.name 的值來選擇要做什麼。而不必寫多個 onChange 函式

    例如:

    class Reservation extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          isGoing: true,
          numberOfGuests: 2
        };
    
        this.handleInputChange = this.handleInputChange.bind(this);
      }
    
      handleInputChange(event) {
        const target = event.target;
        const value = target.type === 'checkbox' ? target.checked : target.value;
        const name = target.name;
    
        this.setState({
          [name]: value
        });
      }
    
      render() {
        return (
          <form>
            <label>
              Is going:
              <input
                name="isGoing"
                type="checkbox"
                checked={this.state.isGoing}
                onChange={this.handleInputChange} />
            </label>
            
            <label>
              Number of guests:
              <input
                name="numberOfGuests"
                type="number"
                value={this.state.numberOfGuests}
                onChange={this.handleInputChange} />
            </label>
          </form>
        );
      }
    }
    
    ReactDOM.render(
      <Reservation />,
      document.getElementById('root')
    );
    複製程式碼

    handleInputChange() 方法中,注意我們如何使用ES6計算的屬性名稱語法來更新與給定輸入名稱相對應的 state(狀態) 鍵:

    const name = target.name;
    
    this.setState({
      [name]: value
    });
    複製程式碼

狀態提升(Lifting State Up)

  1. 在一個 React 應用中,對於任何可變的資料都應該循序“單一資料來源”原則。通常情況下,state 首先被新增到需要它進行渲染的元件。然後,如果其它的元件也需要它,你可以提升狀態到它們最近的祖先元件。你應該依賴 從上到下的資料流向 ,而不是試圖在不同的元件中同步狀態。

    提升狀態相對於雙向繫結方法需要寫更多的“模板”程式碼,但是有一個好處,它可以更方便的找到和隔離 bugs。由於任何 state(狀態) 都 “存活” 在若干的元件中,而且可以分別對其獨立修改,所以發生錯誤的可能大大減少。另外,你可以實現任何定製的邏輯來拒絕或者轉換使用者輸入。

    如果某個東西可以從 props(屬性) 或者 state(狀態) 得到,那麼它可能不應該在 state(狀態) 中。

    狀態提升:子元件要渲染的資料不定義在自身 state 中,而是定義在最近的公共父元件中。該資料由父元件通過 props 傳遞給子元件。當子元件發生改變時,觸發父元件的 onChange() 方法,父元件更改 state ,引起子元件資料改變,從而達到A子元件資料變化時B子元件資料跟著變化的效果。)

組合 VS 繼承(Composition vs Inheritance)

  1. 如果要在元件之間重用非 U I功能,我們建議將其提取到單獨的 JavaScript 模組中。元件可以匯入它並使用該函式,物件或類,而不擴充套件它。

React 的程式設計思想

  1. 如何拆分元件呢?

    其實只需要像拆分一個新方法或新物件一樣的方式即可。一個常用的技巧是 單一職責原則 ,即一個元件理想情況下只處理一件事。如果一個元件持續膨脹,就應該將其拆分為多個更小的元件中。


寫在最後:強烈建議自己讀一遍 React中文文件 (有些翻譯錯誤,不影響閱讀,有能力可以去讀原版。 O(∩_∩)O哈哈~)

相關文章