新手React開發人員容易作錯的5件事

1_Y4vpCQT5-SSNPGnLKZLFYg.png
請勿執行的操做以及如何解決的方法,這部份內容是針對React的新手開發人員提供的。javascript

1.忘記大寫React組件

考慮一下這段代碼,它建立一個簡單的div,其中包含父組件的標題。裏面有一個子組件,其中包含帶有一些文本的div。html

class childComponent extends React.Component {
  render() {
    return (
      <div className='childDiv'>
        <p>Child Component</p>
      </div>
    );
  }
}

class ParentComponent extends React.Component {
  render() {
    return (
      <div className='parentDiv'>
        <h1 className='parentHeader'>Parent Component</h1>
        <childComponent />
      </div>
    );
  }
}

export default ParentComponent;

您認爲代碼運行時會出現什麼?前端

childComponent 未渲染。它去哪兒了?代碼編譯成功,終端也沒有錯誤。java

再次查看子組件的代碼。注意組件的名稱,你注意到什麼不一樣了嗎?react

在瀏覽器中打開控制檯,瀏覽器控制檯警告的大小寫不正確web

事實證實,React將小寫組件視爲DOM標記。若是你是React的新手,你可能已經錯過了React文檔中的這個小細節。面試

若是不瞭解這一點,初學者經常會陷入這樣的困惑:即他們的代碼編譯沒有任何錯誤,到底哪裏出了問題?segmentfault

解決方法很簡單,大寫您的組件。瀏覽器

2.錯誤地調用收到的props

要訪問由父組件傳入的prop,子組件必須確保它們調用了正確的prop名稱。安全

還可使用另外一個變量名將Props傳遞給子組件。考慮如下代碼片斷:

class ChildComponent extends React.Component {
  render() {
    const { randomString } = this.props;

    return (
      <div className='childDiv'>
        <p>{randomString}</p>
      </div>
    );
  }
}

class ParentComponent extends React.Component {
  render() {
    const randomString = 'lorem ipsum';
    
    return (
      <div className='parentDiv'>
        <h1 className='parentHeader'>Parent Component</h1>
        <ChildComponent mainText={randomString} />
      </div>
    );
  }
}

儘管此代碼能夠編譯並運行無誤,但 ChildComponent 內不會渲染任何文本。

<ChildComponent mainText={randomString} />

仔細看看這一行代碼,在 ParentComponent 中聲明的變量 randomString 做爲名爲 mainText 的prop傳遞給 ChildComponent

然而,ChildComponent 試圖從它收到的prop中訪問 randomString。因爲它僅接收 mainText 做爲prop,所以將致使未定義的值分配給在 ChildComponent 中聲明的 randomString。結果,其 <p>標記內未呈現任何內容。

注意哪些prop被傳遞到您的組件中,並相應地訪問它們。這將在調試期間爲您節省一些沒必要要的麻煩。

3.傳遞不正確的Props類型

若是所接收的prop不是預期的類型,那麼依賴於這些接收prop的組件可能會有不一樣的行爲。

class ChildComponent extends React.Component {
  render() {
    const { showIntro, showBody } = this.props;

    return (
      <div className='childDiv'>
        {showIntro && <p>Hello!</p>}
        {showBody && <p>Spot the mistake!</p>}
      </div>
    );
  }
}

考慮這個有兩個prop的 ChildComponentshowIntroshowBody。它顯示「你好!和「發現錯誤!」只有當showIntroshowBody 分別設置爲 true 時纔會這樣。

ChildComponent 但願將兩個布爾值做爲prop傳遞。若是在父組件中執行相似的操做,會發生什麼狀況?

<ChildComponent showIntro='false' showBody='false' />
<ChildComponent showIntro={'false'} showBody={'false'} />
<ChildComponent showIntro={false} showBody={false} />

在prop中使用了不一樣的引號和大括號。可是,它們的行爲將不一樣。看看這個:

前兩個 ChildComponent 都渲染了兩個 <p> 標記,而最後一個 ChildComponent 沒有渲染。

做爲prop傳遞的 'false'{'false'} 會致使無心中爲 showIntroshowBody 分配了一個值爲 false 的字符串,而不是布爾值 false

對於前兩個 ChildComponent,將 showIntroshowBody 都計算爲 true

這是因爲 && 運算符的隱式強制類型轉換。當 && 運算符檢查 showIntroshowBody(均爲字符串)時,兩個字符串都將強制爲 true

最後一個 ChildComponent 接收到布爾值 false,所以它沒有正確渲染任何內容。

console.log(`showIntro type: ${typeof showIntro}`);
console.log(`showIntro evaluated to: ${showIntro && true}`);
console.log(`showBody type: ${typeof showBody}`);
console.log(`showBody evaluated to: ${showBody && true}`);

爲了確認這一點,咱們運行 console.log() 來檢查每一個 ChildComponent 中prop的運行結果。

正如這裏所演示的,初學者在將prop傳遞給其餘組件時可以區分使用引號和花括號之間的區別是很是重要的。

您可使用引號來傳遞字符串文字。

<MyComponent data='Hello World!'/> // passing in a String

花括號用於傳遞JavaScript表達式。

<MyComponent data={2468} /> // passing in a Number
<MyComponent data={true} /> // passing in a Boolean

如下是Reac文檔中的一些注意事項:

將JavaScript表達式嵌入屬性中時,請勿在大括號周圍加上引號。您應該使用引號(用於字符串值)或大括號(用於表達式),但不要在同一屬性中都使用引號。

4.在render()內部調用setState()

下圖無限循環錯誤消息

儘管您的組件中沒有 componentWillUpdate()componentWillUpdate(),您仍可能遇到此錯誤。當您在 render() 函數中調用 setState() 時也會發生此錯誤。

爲何會這樣?每次調用 setState() 時,React將經過調用 render() 從新渲染。您的 render() 函數內部是什麼? setState()。你看到結果了嗎?一個無限循環。

只需將 setState() 調用移到 render() 函數以外便可。

若是在組件掛載後必須初始化狀態(也許是從API端點提取數據),請在 componentDidMoun() 中進行。

若是能夠在組件掛載以前初始化狀態,也可使用構造函數來完成。

5.setState()的異步性

在調試時,一般使用 console.log() 打印值。可是,當代碼異步運行時,這不能很好地工做。

handleCounterIncrement = () => {
  const { counter } = this.state;
  console.log(`Before update: ${counter}`);
  this.setState({ counter: counter + 1 });
  console.log(`After update: ${counter}`);
};

你之前試過這樣作嗎?壞消息——setState() 調用是異步的。不能保證給定的代碼將按順序執行。它可能致使以下輸出:

在執行 setState() 以前執行了兩個 console.log() 調用。所以,它兩次打印前一個狀態的值。

若是但願在調用 setState() 以前和以後檢查狀態的值,請在 setState() 中將回調做爲第二個參數傳遞。

handleCounterIncrement = () => {
  const { counter } = this.state;
  console.log(`before update: ${counter}`);
  this.setState({ counter: counter + 1 }, () => {
      console.log(`after update: ${this.state.counter}`);
  });
};

回調將在 setState() 完成後執行,從而爲 console.log() 提供同步行爲。


文章首發《前端外文精選》微信公衆號

1.png

繼續閱讀其餘高贊文章


相關文章
相關標籤/搜索