React 基礎知識點總結

零、介紹

React.js 是一個幫助你構建頁面 UI 的庫。若是你熟悉 MVC 概念的話,那麼 React 的組件就至關於 MVC 裏面的 View。若是你不熟悉也不要緊,你能夠簡單地理解爲,React.js將幫助咱們將界面分紅了各個獨立的小塊,每個塊就是組件,這些組件之間能夠組合、嵌套,就成了咱們的頁面。css

一個組件的顯示形態和行爲有多是由某些數據決定的。而數據是可能發生改變的,這時候組件的顯示形態就會發生相應的改變。而 React.js 也提供了一種很是高效的方式幫助咱們作到了數據和組件顯示形態之間的同步。html

React.js 不是一個框架,它只是一個庫。它只提供 UI (view)層面的解決方案。在實際的項目當中,它並不能解決咱們全部的問題,須要結合其它的庫,例如 ReduxReact-router 等來協助提供完整的解決方法。node

1、Hello World

create-react-app 是來自於 Facebook 出品的零配置命令行工具,可以幫你自動建立基於Webpack+ES6 的最簡易的 React 項目模板。react

npm install -g create-react-app 

create-react-app my-app 
cd my-app/ 
npm start 
複製代碼

執行完上述命令以後,你能夠直接打開 http://localhost:3000,便可以看到你 React APP 的運行效果:git

create-react-app

目錄結構:es6

my-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│   ├── favicon.ico
│   ├── index.html
│   └── manifest.json
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    └── serviceWorker.js
複製代碼

一個簡單 Hello World 的例子:shell

ReactDOM.render(
    <h1>Hello, world!</h1>,
    document.getElementById('root')
);
複製代碼

2、JSX 簡介

JSX —— React.js 描述頁面 UI 的方式。看起來,JSX 有點像模板語言,其實它是由 React 內部實現的。瀏覽器中,看到的 JSX 內容轉換成 html 顯示了出來。npm

一、在 JSX 中使用表達式

index.js :json

import React from 'react'
import ReactDOM from 'react-dom'

const user = {
  firstName: 'React',
  lastName: 'Hello'
}

const formatName = user => `${user.firstName} ${user.lastName}`
const element = <h1>Hello, {formatName(user)}</h1>

ReactDOM.render(element, document.getElementById('root'))
複製代碼

推薦在 JSX 代碼的外面擴上一個小括號,這樣能夠防止 分號自動插入bug數組

二、JSX 自己其實也是一種表達式

在編譯以後,JSX 其實會被轉化爲普通的 JavaScript 對象。那就能夠在 if 或者 for 語句裏使用 JSX,將它賦值給變量,看成參數傳入,做爲返回值也能夠:

index.js

import React from 'react'
import ReactDOM from 'react-dom'

const user = {
    firstName: 'E2E',
    lastName: 'team'
}

const formatName = user => `${user.firstName} ${user.lastName}`

const getGreeting = (user) => {
    if (user) {
        return <h1>Hello, {formatName(user)}!</h1>;
    }
    return <h1>Hello, Stranger.</h1>;
}

const element = <div>{getGreeting(user)}!</div>

ReactDOM.render(element, document.getElementById('root'))
複製代碼

三、JSX 嵌套

若是 JSX 標籤是閉合式的,那麼你須要在結尾處用 />, 就好像 XML/HTML 同樣:

const element = <img src={user.avatarUrl} />; 複製代碼

JSX 標籤一樣能夠相互嵌套:

const element = (
  <div> <div>頭像</div> <h1>Hello, {formatName(user)}!</h1> </div>
)
複製代碼

注意:多行的 jsx 要用小括號包裹,裏面若是有多個 DOM 節點,也須要用一個 DOM 節點包裹起來,因此這裏加了最外面的 div

四、JSX 屬性

  • 可使用引號來定義以字符串爲值的屬性:
const element = <div tabIndex="0"></div>;
複製代碼

注意:因爲相對HTML 而言,JSX 更加相似於JavaScript, React DOM 使用駝峯命名代替HTML中的屬性名。

  • 也可使用大括號來定義以 JavaScript 表達式爲值的屬性:
const element = <img src={user.avatarUrl}></img>;
複製代碼

注意:使用了大括號包裹的 JavaScript 表達式時就不能再到外面套引號了,JSX 會將引號中的內容識別爲字符串而不是表達式。

五、JSX可以防注入攻擊

render() {
    const content = 'First &middot; <i>Second</i>'
    const element = <div>{content}</div>
    return element
}
複製代碼

也就是在執行渲染前,React DOM 會默認將要顯示的內容中有任何的標籤或者腳本都會進行轉義編碼,按照字符串直接顯示出來。 這能夠避免應用被注入,能夠避免XSS攻擊。因此能夠放心地在JSX 當中使用用戶輸入。

若是須要按照 html 顯示的內容,可使用 dangerouslySetInnerHTML 來實現。

const element = <div dangerouslySetInnerHTML={{ __html: content }} /> 複製代碼

六、JSX 表明 Objects

Babel 轉譯器會把 JSX 轉換成一個名爲 React.createElement() 的方法調用。

下面兩種代碼的做用是徹底相同的:

const element = (
  <h1 className="greeting"> Hello, world! </h1>
);
複製代碼
const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);
複製代碼

React.createElement() 這個方法首先會進行一些避免bug的檢查,以後會返回一個相似下面例子中的對象:

// 注意: 如下示例是簡化過的(不表明在 React 源碼中是這樣)
const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world'
  }
};
複製代碼

這樣的對象被稱爲 React 元素。它表明全部能夠在屏幕上看到的東西。React 經過讀取這些對象來構建 DOM 並保持數據內容一致。

3、元素

元素( element )是一個 React 應用的最小組成單元。

一、將元素渲染到DOM中

index.js

import React from 'react'
import ReactDOM from 'react-dom'

const element = <h1>Hello, world</h1>

ReactDOM.render(element, document.getElementById('root'))
複製代碼

這裏 element 就是一個元素, 元素描述了咱們在屏幕上會看到什麼。React 元素不是組件,組件由元素構成。

能夠經過 ReactDOM.render 把元素渲染到 DOM 中,idroot 的這個節點在 index.html 中。

瀏覽器中,能夠看到 element 元素顯示到了頁面上。

二、React只會更新必要的內容

Index.js :

import React from 'react';
import ReactDOM from 'react-dom';

const tick = () => {
  const element = (
    <div> <h1>Hello, world!</h1> <h2>It is {new Date().toLocaleTimeString()}.</h2> </div>
  )
  ReactDOM.render(element, document.getElementById('root'))
}

setInterval(tick, 1000)
複製代碼

更新必要部分

4、組件&Props

組件( components )可讓咱們把 UI 分割成獨立的能夠複用的片斷。概念上來說,組件相似於 JS 的函數,它接收任意的輸入(也就是 props ,屬性),返回 React 元素。

一、函數式組件

定義一個組件最簡單的方式是寫一個 JS 的函數:

index.js :

import React from 'react'
import ReactDOM from 'react-dom'

const Welcome = props => {
  return <h1>Hello, {props.name}</h1>
}
const element = <Welcome name="Sara" /> ReactDOM.render(element, document.getElementById('root')) 複製代碼

這個函數就是一個完整的 React 組件,由於它接收一個 props 對象做爲參數,返回一個 React 元素。這樣的組件叫作函數式組件。

二、class 式組件

另一個定義組件的方式就是使用 ES6 的 class:

index.js

import React from 'react'
import ReactDOM from 'react-dom'

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>
  }
}

const element = <Welcome name="Sara" /> ReactDOM.render(element, document.getElementById('root')) 複製代碼

從 React 的角度,上面兩個組件是等價的。不過 class 式組件功能會多一些。

三、組件的組合

組件能夠在它的輸出中引用其它組件,這就可讓咱們用同一組件來抽象出任意層次的細節。在React應用中,按鈕、表單、對話框、整個屏幕的內容等,這些一般都被表示爲組件。

例如,咱們能夠建立一個App組件,用來屢次渲染Welcome組件:

index.js

import React from 'react'
import ReactDOM from 'react-dom'

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>
  }
}

const App = () => {
  return (
    <div>
      <Welcome name="Sara" />
      <Welcome name="Cahal" />
      <Welcome name="Edite" />
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))
複製代碼

瀏覽器中,顯示了三個 Welcome

5、State&生命週期

一、class 式組件中才能用 state

class 式組件要比函數式組件功能多,使用 state 就是隻能用在 class 式組件中的功能。

index.js :

import React from 'react'
import ReactDOM from 'react-dom'

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>
    )
  }
}
const element = <Clock /> ReactDOM.render(element, document.getElementById('root')) 複製代碼

Clock 是一個 class 式組件。裏面初始化了 state 值。而後 render 函數中,顯示出了這個 state 值。

二、給 class 添加生命週期方法

每當 Clock 組件第一次加載到 DOM 中的時候,咱們都想生成定時器,這在 React 中被稱爲掛載

一樣,每當 Clock 生成的這個 DOM 被移除的時候,咱們也會想要清除定時器,這在 React 中被稱爲卸載

index.js

import React, { Component } from 'react'
import ReactDOM from 'react-dom'

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

  componentDidMount() {
    this.timerID = setInterval(this.tick, 1000)
  }

  componentWillUnmount() {
    clearInterval(this.timerID)
  }

  tick = () => {
    this.setState({
      date: new Date()
    })
  }

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

ReactDOM.render(<Clock />, document.getElementById('root')) 複製代碼

組件初次渲染以後,會自動執行 componentDidMount 這個生命週期方法,這裏面咱們設置一個定時器,每秒鐘執行一下 tick 方法。這裏把定時器 id 賦值給了 this.timerID

組件被從 DOM 移除的時候,會自動執行 componentWillUnmount ,這裏面咱們須要清除一下定時器,釋放資源。

來定義關鍵的 tick 函數,裏面的關鍵動做就是更新 state 值。注意必定要用 this.setState 來更新。

瀏覽器中,能夠看到每秒鐘界面顯示時間都會更新。

6、事件處理

一、基本用法

React 元素的事件處理和 DOM元素的很類似。可是有一點語法上的不一樣:

  • React事件綁定屬性的命名採用駝峯式寫法,而不是小寫;
  • 若是採用 JSX 的語法,須要傳入一個函數做爲事件處理函數(推薦使用ES6 的箭頭函數),而不是一個字符串(DOM元素的寫法)。

index.js :

import React, { Component } from 'react'
import ReactDOM from 'react-dom'

class Toggle extends Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make `this` work in the callback
    // this.handleClick = this.handleClick.bind(this);
  }

  handleClick = () => {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }))
  }

  render() {
    return (
      <button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button>
    )
  }
}

ReactDOM.render(<Toggle />, document.getElementById('root')) 複製代碼

注意:類的方法默認是不會綁定 this 的。能夠將 handleClick 直接賦值爲一個 es6 箭頭函數,這樣的好處是裏面直接使用 this 而無需綁定。因爲 this.setState 的異步性,因此參數不能傳入對象,而要傳入一個函數,才能穩妥的基於以前的狀態來得到最新狀態值。

二、給事件處理函數傳參

一般咱們會爲事件處理程序傳遞額外的參數。例如,如果 id 是你要刪除那一行的 id

index.js :

import React from 'react'
import ReactDOM from 'react-dom'

class List extends React.Component {
  deleteRow = id => {
    console.log(id)
  }

  render() {
    return <button onClick={() => this.deleteRow(2)}>Delete Row</button>
  }
}

ReactDOM.render(<List />, document.getElementById('root')) 複製代碼

好比有一個列表,這裏封裝成 List 組件。裏面 deleteRow 須要接受行號,這裏就是 id ,才能知道要刪除哪一行的內容。

若是 deleteRow 中,還想要事件對象:

deleteRow = (id, e) => {
    console.log(id)
  }

  render() {
    return <button onClick={e => this.deleteRow(2, e)}>Delete Row</button>
  }
複製代碼

ES6 參數中拿到 e ,把它做爲第二個參數傳遞給 deleteRow 便可。

7、條件渲染

React 中,你能夠建立不一樣的組件來封裝各類你須要的行爲。而後還能夠根據應用的狀態變化只渲染其中的一部分。

React 中的條件渲染和 JavaScript 中的一致,使用 JavaScript 操做符 if條件運算符來建立表示當前狀態的元素,而後讓 React 根據它們來更新 UI

一、if 條件渲染

index.js :

import React from 'react'
import ReactDOM from 'react-dom'

const UserGreeting = () => <h1>Welcome back!</h1>
const GuestGreeting = () => <h1>Please sign up.</h1>

const Greeting = props => {
  const isLoggedIn = props.isLoggedIn
  if (isLoggedIn) {
    return <UserGreeting />
  }
  return <GuestGreeting />
}

ReactDOM.render(<Greeting isLoggedIn={true} />, document.getElementById('root'))
複製代碼

先定義兩個函數式組件,一個是跟已經登錄的用戶打招呼,另外一個跟訪客打招呼。下面定義 Greeting 組件。隨着 isLoggedIn 的值的不一樣,會顯示出不一樣的內容。

瀏覽器中,當 isLoggedIn 設置爲 truefalse ,會分別顯示不一樣的打招呼信息。

二、元素變量

你可使用變量來儲存元素。它能夠幫助你有條件的渲染組件的一部分,而輸出的其餘部分不會更改。

index.js :

import React, { Component } from 'react'
import ReactDOM from 'react-dom'

const UserGreeting = () => <h1>Welcome Back</h1>
const GuestGreeting = () => <h1>Please Sign Up</h1>
const LoginButton = props => <button onClick={props.onClick}>Login</button>
const LogoutButton = props => <button onClick={props.onClick}>Logout</button>

const Greeting = props => {
    const { isLoggedIn } = props
    if (isLoggedIn) {
        return <UserGreeting />
    }
    return <GuestGreeting />
}

class LoginControl extends Component {
  state = {
    isLoggedIn: false
  }

  handleLoginClick = () => {
    this.setState({
      isLoggedIn: true
    })
  }
  handleLogoutClick = () => {
    this.setState({
      isLoggedIn: false
    })
  }

  render() {
    const { isLoggedIn } = this.state

    let button = null
    if (isLoggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />
    } else {
      button = <LoginButton onClick={this.handleLoginClick} />
    }
    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    )
  }
}

ReactDOM.render(<LoginControl />, document.getElementById('root'))
複製代碼

添加兩個按鈕組件進來,一個是登陸,一個是登出。建立一個 LoginControl 組件,初始化 isLoggedIn ,添加登陸和登出對應的處理函數,裏面對 isLoggedIn 狀態值進行了修改。

三、與運算符 &&

JavaScript 的邏輯與 &&,它能夠方便地條件渲染一個元素。

index.js :

import React from 'react'
import ReactDOM from 'react-dom'

const Mailbox = props => {
  const { unreadMessages } = props
  return (
    <div> <h1>Hello!</h1> {unreadMessages.length > 0 && ( <h2>You have {unreadMessages.length} unread messages.</h2> )} </div>
  )
}

const messages = ['React', 'Re: React', 'Re:Re: React']
ReactDOM.render(
  <Mailbox unreadMessages={messages} />, document.getElementById('root') ) 複製代碼

定義 Mailbox 組件,屬性中拿到未讀郵件的數組,下面用 && 號實現 if 的效果,若是未讀郵件數量大於 0,就顯示未讀郵件的數量;若是數量爲 0,那麼大括號裏面內容就求值爲 undefined ,也就是什麼都不會顯示了。

四、三目運算符

在下面的例子中,咱們用它來有條件的渲染一小段文本:

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div> The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in. </div>
  );
}
複製代碼

一樣它也能夠用在較大的表達式中:

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
      )}
    </div>
  );
}
複製代碼

五、阻止組件渲染

在極少數狀況下,你可能但願隱藏組件,即便它被其餘組件渲染。讓 render 方法返回 null 而不是它的渲染結果便可實現。

index.js :

import React from 'react'
import ReactDOM from 'react-dom'

const 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 }
    }

    handleToggleClick = () => {
        this.setState({
            showWarning: !this.state.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') ); 複製代碼

8、列表 & Keys

一、渲染多個組件

先看下在 Javascript 中如何轉化列表:

咱們使用 map()函數讓數組中的每一項翻倍,咱們獲得了一個新的數列doubled

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log(doubled);
複製代碼

React中,把數組轉化爲數列元素的過程是類似的:

index.js :

import React from 'react'
import ReactDOM from 'react-dom'

const messages = ['hello', 'hi', 'how are you']

const List = props => {
  const { messages } = props

  const list = messages.map(t => <li>{t}</li>)
  return <ul>{list}</ul>
}

ReactDOM.render(<List messages={messages} />, document.getElementById('root'))
複製代碼

注:此時打開瀏覽器控制檯會有報錯信息:Warning: Each child in an array or iterator should have a unique "key" prop. 。緣由是每個列表條目都應該有一個獨一無二的 key

二、Key

把數據的 id 做爲 key 是很是常見的作法:

index.js

import React from 'react'
import ReactDOM from 'react-dom'

const messages = [
  {
    id: 1,
    text: 'React'
  },
  {
    id: 2,
    text: 'Re: React'
  },
  {
    id: 3,
    text: 'Re:Re: React'
  }
]

const List = props => {
  const { messages } = props
  const list = messages.map(t => <li key={t.id}>{t.text}</li>)
                            
  return <ul>{list}</ul>
}

ReactDOM.render(<List messages={messages} />, document.getElementById('root'))
複製代碼

一個元素的 key 最好是這個元素在列表中擁有的一個獨一無二的字符串。一般,咱們使用來自數據的 id 做爲元素的key。

實際開發中的數據通常都是配有 id 的,將 id 做爲 key 是一個很好的作法。若是用數組 index 做爲 key 也是勉強能夠的,可是因爲 index 可能會隨着數組元素的增減發生變化,若是列表能夠從新排序,這會致使渲染變得很慢。

9、表單

當用戶提交表單時,HTML 的默認行爲會使這個表單跳轉到一個新頁面。在 React 中亦是如此。

但大多數狀況下,咱們都會構造一個處理提交表單並可訪問用戶輸入表單數據的函數。實現這一點的標準方法是使用一種稱爲受控組件的技術。

一、受控組件

<input><select> 都要綁定一個 change 事件,每當表單的狀態發生變化,都會被寫入組件的 state 中,這種組件在 React 中被稱爲受控組件。

二、form 基本用法

index.js :

import React, { Component } from 'react'
import ReactDOM from 'react-dom'

class Form extends Component {
  constructor(props) {
    super(props);
    this.state = { username: '' }
  }

  handleChange = e => {
    this.setState({
      username: e.target.value
    })
  }

  handleSubmit = e => {
    console.log(this.state.username)
    e.preventDefault()
  }

  render() {
    return (
      <div> username: <input type="text" value={this.state.username} onChange={this.handleChange} /> <button onClick={this.handleSubmit}>提交</button> </div> ) } } ReactDOM.render(<Form />, document.getElementById('root')) 複製代碼

因爲 value 屬性是在咱們的表單元素上設置的,所以顯示的值將始終爲 React 數據源上this.state.value 的值。因爲每次按鍵都會觸發 handleChange 來更新當前 React 中的 state,所展現的值也會隨着不一樣用戶的輸入而更新。

三、處理多個輸入

你有處理多個受控的 input 元素時,你能夠經過給每一個元素添加一個 name 屬性,來讓處理函數根據 event.target.name 的值來選擇作什麼。

import React, { Component } from 'react'
import ReactDOM from 'react-dom'

class Form extends Component {
  constructor(props) {
    super(props);
    this.state = { username: '', email: '' }
  }

  handleChange = event => {
    const { value, name } = event.target

    this.setState({
      [name]: value
    })
  }

  handleSubmit = e => {
    console.log(`${this.state.username} ${this.state.email}`)
    e.preventDefault()
  }

  render() {
    return (
      <div>
        Username:
        <input
          name="username"
          type="text"
          value={this.state.username}
          onChange={this.handleChange}
        />
        <br />
        Email:
        <input
          name="email"
          type="text"
          value={this.state.email}
          onChange={this.handleChange}
        />
        <br />
        <button onClick={this.handleSubmit}>提交</button>
      </div>
    )
  }
}

ReactDOM.render(<Form />, document.getElementById('root'))
複製代碼
相關文章
相關標籤/搜索