新手學習 react 迷惑的點(一)

網上各類言論說 React 上手比 Vue 難,可能難就難不能深入理解 JSX,或者對 ES6 的一些特性理解得不夠深入,致使以爲有些點難以理解,而後說 React 比較難上手,還反人類啥的,因此我打算寫兩篇文章來說新手學習 React 的時候容易迷惑的點寫出來,若是你還以其餘的對於學習 React 很迷惑的點,能夠在留言區裏給我留言。javascript

爲何要引入 React

在寫 React 的時候,你可能會寫相似這樣的代碼:html

import React from 'react'

function A() {
  // ...other code
  return <h1>前端桃園</h1>
}
複製代碼

你確定疑惑過,上面的代碼都沒有用到 React,爲何要引入 React 呢?前端

若是你把 import React from ‘react’ 刪掉,還會報下面這樣的錯誤:java

7F6E506E-3025-401D-A492-3B501F8081C6

那麼到底是哪裏用到了這個 React,致使咱們引入 React 會報錯呢,不懂這個緣由,那麼就是 JSX 沒有搞得太明白。react

你能夠講上面的代碼(忽略導入語句)放到在線 babel 裏進行轉化一下,發現 babel 會把上面的代碼轉化成:git

function A() {
  // ...other code
  return React.createElement("h1", null, "前端桃園");
}
複製代碼

由於從本質上講,JSX 只是爲 React.createElement(component, props, ...children) 函數提供的語法糖。github

爲何要用 className 而不用 class

  1. React 一開始的理念是想與瀏覽器的 DOM API 保持一直而不是 HTML,由於 JSX 是 JS 的擴展,而不是用來代替 HTML 的,這樣會和元素的建立更爲接近。在元素上設置 class 須要使用 className 這個 API:瀏覽器

    const element = document.createElement("div")
    element.className = "hello" 
    複製代碼
  2. 瀏覽器問題,ES5 以前,在對象中不能使用保留字。如下代碼在 IE8 中將會拋出錯誤:微信

    const element = {
      attributes: {
        class: "hello"
      }
    } 
    複製代碼
  3. 解構問題,當你在解構屬性的時候,若是分配一個 class 變量會出問題:babel

    const { class } = { class: 'foo' } // Uncaught SyntaxError: Unexpected token }
    const { className } = { className: 'foo' } 
    const { class: className } = { class: 'foo' } 
    複製代碼

其餘討論可見:有趣的話題,爲何jsx用className而不是class

爲何屬性要用小駝峯

由於 JSX 語法上更接近 JavaScript 而不是 HTML,因此 React DOM 使用 camelCase(小駝峯命名)來定義屬性的名稱,而不使用 HTML 屬性名稱的命名約定。

來自 JSX 簡介

爲何 constructor 裏要調用 super 和傳遞 props

這是官網的一段代碼,具體見:狀態(State) 和 生命週期

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }

  render() {
    return (
      <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div>
    );
  }
}
複製代碼

並且有這麼一段話,不只讓咱們調用 super 還要把 props 傳遞進去,可是沒有告訴咱們爲何要這麼作。

image-20190901222456704

不知道你有沒有疑惑過爲何要調用 super 和傳遞 props,接下來咱們來解開謎題吧。

爲何要調用 super

其實這不是 React 的限制,這是 JavaScript 的限制,在構造函數裏若是要調用 this,那麼提早就要調用 super,在 React 裏,咱們經常會在構造函數裏初始化 state,this.state = xxx ,因此須要調用 super。

爲何要傳遞 props

你可能覺得必須給 super 傳入 props,不然 React.Component 就無法初始化 this.props

class Component {
  constructor(props) {
    this.props = props;
    // ...
  }
}
複製代碼

不過,若是你不當心漏傳了 props,直接調用了 super(),你仍然能夠在 render 和其餘方法中訪問 this.props(不信的話能夠試試嘛)。

爲啥這樣也行?由於React 會在構造函數被調用以後,會把 props 賦值給剛剛建立的實例對象:

const instance = new YourComponent(props);
instance.props = props;
複製代碼

props 不傳也能用,是有緣由的。

但這意味着你在使用 React 時,能夠用 super() 代替 super(props) 了麼?

那仍是不行的,否則官網也不會建議你調用 props 了,雖然 React 會在構造函數運行以後,爲 this.props 賦值,但在 super() 調用以後與構造函數結束以前, this.props 仍然是無法用的。

// Inside React
class Component {
  constructor(props) {
    this.props = props;
    // ...
  }
}

// Inside your code
class Button extends React.Component {
  constructor(props) {
    super(); // 😬 忘了傳入 props
    console.log(props); // ✅ {}
    console.log(this.props); // 😬 undefined
  }
  // ...
}

複製代碼

要是構造函數中調用了某個訪問 props 的方法,那這個 bug 就更難定位了。所以我強烈建議始終使用super(props),即便這不是必須的:

class Button extends React.Component {
  constructor(props) {
    super(props); // ✅ We passed props
    console.log(props); // ✅ {}
    console.log(this.props); // ✅ {}
  }
  // ...
}

複製代碼

上面的代碼確保 this.props 始終是有值的。

若是你想避免以上的問題,你能夠經過class 屬性提案 來簡化代碼:

class Clock extends React.Component {
  state = {date: new Date()};

  render() {
    return (
      <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div>
    );
  }
}

複製代碼

更詳細的內容可見Dan 的博客

爲何組件用大寫開頭

前面以及說過了,JSX 是 React.createElement(component, props, …children) 提供的語法糖,component 的類型是:string/ReactClass type,咱們具體看一下在什麼狀況下會用到 string 類型,什麼狀況下用到 ReactClass type 類型

  • string 類型react會以爲他是一個原生dom節點
  • ReactClass type 類型 自定義組件

例如(string):在 jsx 中咱們寫一個

<div></div>

複製代碼

轉換爲js的時候就變成了

React.createElement("div", null)

複製代碼

例如(ReactClass type):在jsx中咱們寫一個

function MyDiv() {
    return (<div><div>)
}
<MyDiv></MyDiv>

複製代碼

轉換爲js的時候就變成了

function MyDiv() {
  return React.createElement("div", null);
}

React.createElement(MyDiv, null);

複製代碼

上邊的例子中若是將MyDiv中的首字母小寫,以下

function myDiv() {
    return (<div><div>)
}
<myDiv></myDiv>

複製代碼

轉換爲 js 的時候就變成了

function myDiv() {
  return React.createElement("div", null);
}

React.createElement("myDiv", null);

複製代碼

因爲找不到 myDiv 這個 dom,因此就會報錯。

後記

這是這個系列的第一篇,這些問題也是在個人一個「React交流羣」裏你們提出來的一些他們剛學 react 的時候容易迷惑的點,下一篇不出意外就是解答如下迷惑的點,若是有其餘的問題想知道的,歡迎在評論區留言。

  • 爲何調用方法要 bind this

  • 爲何要 setState,而不是直接 this.state.xx = oo

  • 爲何setState不是同步

  • 爲何render裏面要用一個父級標籤包裹(沒有 Fragment 之前)


我是桃翁,一個愛思考的前端er,想了解關於更多的前端相關的,請關注個人公號:「前端桃園」,若是想加入交流羣關注公衆號後回覆「微信」拉你進羣

相關文章
相關標籤/搜索