爲何不能在 JSX 裏直接寫 console.log?

本文適合哪些人閱讀

本文從「爲何不能直接在 JSX 裏面寫 console.log」這個問題出發,分析了 React的元素渲染機制,並介紹了幾種在JSX 執行 console.log 語句的姿式,最後還介紹了 React 項目中調試代碼的其餘姿式。javascript

本文適合 React 初學者閱讀,若是你已經能夠熟練使用 React 開發項目,本文對於你來講可能過於簡單。html

爲何會寫這篇文章

爲何會寫這篇文章呢?由於前一陣子在給公司裏面其餘同事(非前端)作 React開發培訓的時候,發現有不少 React 初學者喜歡在代碼中使用 console.log 來調試,而且習慣性地寫成下面這樣:前端

// 這裏咱們指望將 menus 這個數據打印出來查看
return (
  <div> <h1>Hello World</h1> console.log(menus) </div>
)
複製代碼

可是上面這個寫法 React 能讓你經過嗎?java

答案是否認的。讓咱們來看看這樣寫實際上會渲染出什麼效果:react

image-20191211134413837
image-20191211134413837

這顯然不符合咱們最初的預期——將 menus 數據顯示在頁面中,讓咱們能夠看到 menus中具體有些什麼數據。web

那麼爲何會出現這種結果呢?chrome

這就要從 React 的元素渲染機制提及了。api

React 的元素渲染機制

首先來看看對於<h1>Hello World<h1> 這個語句,React 是怎麼渲染的:數組

React.createElement(
  'h1',
  null,
  'Hello World'
)
複製代碼

怎麼理解上面這段代碼呢?瀏覽器

JSX 是一個JavaScript 的語法擴展,咱們利用JSX這個語法糖來更好地描述 UI 和數據的交互形式。可是咱們最終要交給瀏覽器去渲染的,應該是html文件,這纔是瀏覽器能識別的,因此咱們須要利用 Babel 來作語法轉譯。

Babel 會把 JSX 轉譯成一個名爲React.createElement() 的函數調用。

讓咱們來看看 React.createElement() 函數的參數定義:

React.createElement(
  type,
  [props],
  [...children]
)
複製代碼

它接收的第一個參數是 html 的標籤名,第二個參數是 props,第三個參數就是標籤包裹着的全部 children

好了,理解了 React的元素渲染機制以後,咱們再來看看加上console.log以後,完整的渲染語句:

render() {
  return React.createElement(
    'div',
    null,
    React.createElement(
      'h1',
      null,
      'Hello'
    ),
    'console.log(menus)'
  )
}
複製代碼

能夠看到,對於 div標籤來講,它的孩子有兩個:由h1 標籤包裹的 Hello World 文本<h1>Hello World<h1> 以及沒有任何標籤包裹的 console.log(menus) 文本(是的!在這裏,console.log(menus) 語句已經被 React.createElement 函數識別成了 文本!!!)。

因此,Babel轉譯後交給瀏覽器渲染的節點就是下面這樣的:

image-20191211141414092
image-20191211141414092

如今,咱們再回過頭來看文章開頭的那個渲染結果就一點都不奇怪了。

image-20191211134413837
image-20191211134413837

以上的 Babel 轉譯過程你能夠點擊這裏來體驗

若是我必定要在 JSX 中打印出數據呢

哼,雖然搞懂了爲何不能在JSX中直接使用 console.log 這個打印語句來打印數據,可是有的時候咱們就是想要把數據打印出來調試(大部分前端 er 都習慣使用console.log 來調試代碼 ),怎麼辦呢?

還真有幾個好辦法,下面就聽我細細道來。

在 JSX 以外打印數據

第一種方法最簡單了,應該你們都想獲得——你能夠在JSX以外寫 console.log 啊。

render(){
  console.log(menus)
  return console.log(menus) || (
    <div> <h1>Hello World</h1> </div>
  )
}
複製代碼

若是你要打印的數據是對象或者數組,你還可使用 console.table 這個API 來打印,效果更佳:

image-20191211143630652
image-20191211143630652

使用 { } 來包裹 console.log 語句

首先咱們要明確一個點:

JSX 語法中,你能夠在大括號內放置任何有效的 JavaScript 表達式。例如,2 + 2user.firstNameformatName(user) 都是有效的 JavaScript 表達式。

因此,你能夠這樣寫:

render(){
  return (
    <div> <h1>Hello World</h1> { console.log(menus) } </div>
  )
}
複製代碼

使用 || 操做符

這個方法就比較秀了,雖然不難也不復雜,可是通常人可能想不到。

咱們能夠這樣寫:

render(){
  return console.log(menus) || (
    <div> <h1>Hello World</h1> </div>
  )
}
複製代碼

好了,看看瀏覽器渲染結果:

image-20191211142711353
image-20191211142711353

正確!沒有渲染出什麼咱們不想要的東西。

再看看控制檯:

image-20191211142801259
image-20191211142801259

也按照咱們的預期打印出了 menus 數據!

爲何能夠這樣寫呢?

由於 console.log 的返回值是 undefined,咱們能夠巧妙地利用這一點再結合 || 操做符短路的屬性,天然而然地實現既打印數據又正確渲染 UI 的效果。

使用JSON.stringify

第二種方法就是咱們能夠直接用JSON.stringify 將數據包裝一下,而後放在 div 標籤中渲染,這樣咱們就能夠直接在界面上看到數據,而不用一直盯着控制檯。

render(){
  return console.log(menus) || (
    <div> <h1>Hello World</h1> <div>{JSON.stringify(menus)}</div> </div>
  )
}
複製代碼

固然,這種方式更適合於打印比較小的數據。

有什麼更好的調試方法嗎

若是你已經看到了這裏,恭喜你!你已經掌握了四種在 React 使用執行 console.log 語句的姿式了~

img
img

不過使用 console.log 終歸不是一種優雅的方式,下面簡單介紹幾種 React 項目調試代碼的方式:

由於篇幅關係這裏就不展開講了,感興趣的同窗能夠點擊連接進去看下官方文檔瞭解下。

相關文章
相關標籤/搜索