1. 程式人生 > >redux 官方示例 todomvc 兩個警告修復

redux 官方示例 todomvc 兩個警告修復

題外話:
本人有輕度程式碼潔癖,只要有警告,我會認為程式碼還有需要完善的地方,只要有時間我就會著手去解決它,去了解其背後的原因,瞭解為什麼會發出警告,以及解決方案是什麼,最終消除這些影響程式碼質量的“隱患”。
通過解決這類問題,會讓自己對相關程式碼的理解更加深入,做到知其然,並且知其所以然,同時,能夠讓自己對相關知識點印象深刻。

兩個警告相關的 PR

備註:PR 合併之後,最新版已經沒有這兩個警告了

官方 todomvc 示例原始碼

其實改動很小,主要看解決思路和理解相關的知識點。

兩個大大的紅色警告

examples/todomvc/src/components/TodoTextInput.js

完整警告資訊如下:

Warning: Received the string `true` for the boolean attribute `autoFocus`. Although this works, 
it will not work as expected if you pass the string "false". Did you mean autoFocus={true}?
    in input (at TodoTextInput.js:40)
    in TodoTextInput (at Header.js:8)
    in header (at Header.js:6)
    in Header (created by Connect(Header))
    in Connect(Header) (at App.js:7)
    in div (at App.js:6)
    in App (at src/index.js:13)
    in Provider (at src/index.js:12)

解決

上面的提示資訊,其實已經非常友好了,看重點:Did you mean autoFocus={true}?
看一下報錯的地方的原始碼(TodoTextInput.js:40

  <input className={
    classnames({
      edit: this.props.editing,
      'new-todo': this.props.newTodo
    })}
    type="text"
    placeholder={this.props.placeholder}
    autoFocus="true"
    value={this.state.text}
    onBlur={this.handleBlur}
    onChange={this.handleChange}
    onKeyDown={this.handleSubmit} />

根據友好的提示資訊,將上面的 autoFocus="true" 改為 autoFocus={true} 即可。

examples/todomvc/src/components/MainSection.js

完整警告資訊如下:

index.js:1452 Warning: Failed prop type: You provided a `checked` prop to a form field without an `onChange` handler. 
This will render a read-only field. 
If the field should be mutable use `defaultChecked`. Otherwise, set either `onChange` or `readOnly`.
    in input (at MainSection.js:12)
    in span (at MainSection.js:11)
    in section (at MainSection.js:8)
    in MainSection (created by Connect(MainSection))
    in Connect(MainSection) (at App.js:8)
    in div (at App.js:6)
    in App (at src/index.js:13)
    in Provider (at src/index.js:12)

看一下報錯的地方的原始碼(MainSection.js:12

  <input
    className="toggle-all"
    type="checkbox"
    checked={completedCount === todosCount}
  />

從下面的提示資訊看

You provided a `checked` prop to a form field without an `onChange` handler. This will render a read-only field.

我的理解是:設定了 checked 屬性,但是又沒有提供 onChange 事件來更新它,那麼,將會自動為其設定一個 read-only 屬性。
將上面的程式碼,去掉 className 屬性,如下:

  <input
    type="checkbox"
    checked={completedCount === todosCount}
  />

再看介面,這時候,一個可以看到是否選中狀態的複選框出現了,它確實是只讀的,點選沒有反應,當所有待辦事項變成完成狀態時,該 checkbox 會被設定為選中狀態,否則為非選中狀態。
再看後面的提示:

If the field should be mutable use `defaultChecked`. Otherwise, set either `onChange` or `readOnly` 

我的理解是:如果該 checkbox 是可變的,那麼,請為其設定一個預設值,否則,要麼設定 onChange 事件,要麼設定 readOnly 屬性。
設定預設值,例如設定預設選中,可以這樣:

  <input
    type="checkbox"
    defaultChecked={true}
  />

如果為其設定預設值 defaultChecked,但不動態設定 checked 屬性,是不會有上面的警告的,但我們需要動態為其設定 checked 屬性,這樣在介面上能看出來是否為全部選中狀態(向下的箭頭顏色有差別,更詳細的,請執行起來檢視實際效果)。

很明顯,如果要為其設定 checked 屬性,設定 defaultChecked 是沒有意義的(即使設定了,也還是會報同樣的警告)。
所以,從提示資訊看上,為了消除這個警告,有兩種解決辦法:

  1. 設定 readOnly 屬性。
      <input
        type="checkbox"
        defaultChecked={completedCount === todosCount}
        readOnly
      />
    
  2. 設定一個 onChange 事件,哪怕是一個什麼也不做的“空”事件。
      <input
        type="checkbox"
        defaultChecked={completedCount === todosCount}
        onChange={()=>{}}
      />
    

對於這個例子,設定 readOnly 是最好的方案,本來也是需要只讀的嘛。設定“空”事件有點莫名其妙。

解讀第二個警告

至於為什麼 react 會有這樣的檢查,stackoverflow.com 網站上有一個網友的回答,我認為是比較貼切的,摘錄如下:

Controlled Components

Attributes needed:

  1. value - <input> (not checkbox or radio), <select>, <textbox> or checked for (checkbox or radio).
  2. onChange
  • React handles the condition of the element by updating the value or checked attribute (depending on the element) from the props or the state.
  • We need to notify react when we make a change, like inserting data, or checking the box,
  • so react can update the element’s condition when it rerenders the component.
  • To do so, we must include an onChange handler, in which we will update the state or notify the component’s parent, so it will update the props.
<input
  type="checkbox"
  checked={ this.props.checked }
  onChange={ this.checkboxHandler } 
/>

Uncontrolled Components

Attributes needed:

defaultValue - <input> (not checkbox or radio), <select>, <textbox> or defaultChecked for (checkbox or radio).

React sets the initial value using defaultValue or defaultChecked, and the update of the element’s state is controlled by the user, usually via the DOM using refs.

<input
  type="checkbox"
  defaultChecked={ this.props.checked } 
/>

擴充套件閱讀

是有關可控元件和非可控元件的。