React學習筆記

来源:https://www.cnblogs.com/wuxiaobin/archive/2018/07/31/9395878.html
-Advertisement-
Play Games

一、React初探 es6寫法 "code" es5寫法(遺憾的是現在最新版本的react,已經不再能使用createClass去創建react組件了 "code" ) 核心思想:封裝組件,各個組件維護自己的狀態(state, prop)和UI,當狀態變更,自動重新渲染組件,數據流向是單向的。 需要 ...


一、React初探

es6寫法 code
  import React from 'react';
  import ReactDOM from 'react-dom';
  import PropTypes from 'prop-types';
  
  class App extends React.Component { 
      state = {
          title: '環球大前端'
      }
      render() {
          const { title } = this.state;
          const { name } = this.props
          return (
            <div>
                <h2>{title}</h2>
                <p> Hello {name}! </p>
            </div>
          )
      }
  }
  App.propTypes = {
      name: PropTypes.string
  }
  App.defaultProps = {
      name: '帥氣小伙子'
  }
  ReactDOM.render(<App name="24小清新" />, document.getElementById('app'));
es5寫法(遺憾的是現在最新版本的react,已經不再能使用createClass去創建react組件了 code
var App = React.createClass({
    getDefaultProps: function() {
      return {
        name: '帥氣小伙子'  
      }  
    },
    getInitialState: function() {
        return {
            title: '環球大前端'
        }
    },
    render: function() {
      return (
        <div>
            <h2>{this.state.title}</h2>
            <p> Hello {this.props.name}! </p>
        </div>
      )
    }
})
React.render(<App name="24小清新" />, document.getElementById('app'));

核心思想:封裝組件,各個組件維護自己的狀態(state, prop)和UI,當狀態變更,自動重新渲染組件,數據流向是單向的。

需要明白的幾個基礎概念:

1、什麼是JSX?

2、如何修改組件state,從而修改組件UI?

3、事件處理

對於上述那些既不是字元串也不是 HTML的的標簽語法,被稱為JSX,是一種 JavaScript 的語法擴展,用來描述用戶界面。

常用的是在JSX中使用表達式,例如 2 + 2, user.firstName, 以及 formatName(user),條件判斷(三目運算符、&&), 數組Map函數遍歷獲取React元素 都是可以使用的。如:

    formatName(user) {
        return `${user.firstName}-${user.name}`;
    }
    const user = {
        firstName: 'wu',
        name: 'shaobin'
    }
    const show = true; //我可以是this.state屬性哦!!!
    const arr = ['xiaobin', 'kaizi', 'liujun'];
    const element = (
      <div>
        <h1>Hello, {formatName(user)}!</h1>
        <h1>Hello, {user.name}!</h1>
        <h1>Hello, { 1 + 1 }!</h1>
        <h1>Hello, { show ? 'I am show' : null }</h1>
        <h1>Hello, { arr.length > 0 && <span>數組長度大於0</span> }</h1>
        {
            arr.map((item, index) => {
                return <span key={item}>item</span>    
            })
        }
        //記住數組Map函數遍歷獲取React元素的時候,必須要記得必須➕keys屬性
        // 為啥呀?
        //Keys可以在DOM中的某些元素被增加或刪除的時候幫助React識別哪些元素髮生了變化。因此你應當給數組中的每一個元素賦予一個確定的標識。沒有唯一值的時候可以使用index,但是官方不建議,會導致渲染變慢。
      </div>
    );
    ReactDOM.render(
      element,
      document.getElementById('root')
    );

切記每個組件的render函數返回的JSX結構都需要根元素去包裹著,當然也有例外,如React.Fragment

對於JSX,react最終經babel的轉換會調用React.createElement相應api轉換成react能識別的對象,如上述例子轉換後得到:

React.createElement(
    'div',
    null,
    React.createElement(
        'h2', //可以是一個html標簽名稱字元串,也可以是也可以是一個 React component 類型
        null,
        title
    ),
    React.createElement(
        'p',
        null,
        ' Hello ',
        name,
        '! '
    )
);

babel查看es6->es5的結果

既然我們可以為組件初始化狀態,也必須要能夠去改變它,以達到改變視圖。
當然this.state.xxx = xxx不會觸發渲染組件的動作,而是使用this.setState({ xxx: xxx })方法來修改狀態,同時多個setState() 調用合併成一個調用能提高性能。

對於事件處理,需要註意的一點就是this的綁定,其他跟普通Dom綁定監聽事件一樣,this的綁定有以下幾種方式:

  1. 在構造函數中使用bind綁定this
  2. 在調用的時候使用bind綁定this
  3. 在調用的時候使用箭頭函數綁定this
  4. 使用屬性初始化器語法綁定this

setState與事件處理的例子

二、React進階

1、有哪些生命周期,生命周期的執行順序?

2、Ref的引用

3、高階組件的使用

生命周期圖示(React16):

Mounting/掛載

constructor()    //React組件的構造函數,用於super(props),初始化state,bind綁定事件等

static getDerivedStateFromProps()

UNSAFE_componentWillMount()    // 組件掛載前(組件渲染到頁面前)

render()    // 渲染函數,不做實際的渲染動作,它只是返回一個JSX描述的結構,生成虛擬Dom樹,執行patch,最終由React來操作渲染過程

componentDidMount()  //組件掛載後(組件渲染到頁面上),可以在這個鉤子添加非同步請求以及定時器,或是socket連接

Updating/更新

UNSAFE_componentWillReceiveProps() // 組件接收到屬性時觸發

static getDerivedStateFromProps()

shouldComponentUpdate(prevProps, prevState)  // 當組件接收到新屬性,或者組件的狀態發生改變時觸發。組件首次渲染時並不會觸發,此鉤子可做性能優化

UNSAFE_componentWillUpdate()  //組件即將被更新時觸發

render() // 渲染函數,不做實際的渲染動作,它只是返回一個JSX描述的結構,生成虛擬新Dom樹,與舊樹進行diff, 執行patch

getSnapshotBeforeUpdate()

componentDidUpdate(prevProps, prevState, snapshot) // 組件被更新完成後觸發,生命周期中由於state的變化觸發請求,在componentDidUpdate中進行

Unmounting/卸載

componentWillUnmount()  // 卸載組件,註銷監聽事件或是定時器,socket關閉

詳細看生命周期例子

補充Tip

getSnapshotBeforeUpdate()static getDerivedStateFromProps()兩個新增生命周期鉤子是被用來代替 UNSAFE_componentWillMount() ,UNSAFE_componentWillUpdate(), UNSAFE_componentWillReceiveProps()三個生命周期的,但是這個三個生命周期仍是可以使用。為什麼勒?React為了1.7版本實現Async Rendering。

Refs 提供了一種方式,用於訪問在 render 方法中創建的 DOM 節點或 React 元素,官方建議少用。獲取Ref有三種場景:


獲取Ref的常用方式(通過this.myRef.current來獲取Dom節點或實例):

class MyComponent extends React.Component {
   constructor(props) {
     super(props);
     this.myRef = React.createRef(); // 調用React.createRef API
   }
   render() {
     return <input ref={this.myRef} />;
   }
}
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return <input ref={(ref) => { this.myRef = ref; }} />;
  }
}

Ref獲取Dom元素例子, Ref獲取React元素(子組件實例)例子

補充Tip: 

對於第三種情況,獲取子組件的Dom節點,官方有提供Forwarding Refs(轉發Ref)的方法,來獲取子組件的Dom節點的Ref,此方法返回的是一個React元素,對應方法為
React.forwardRef((props, ref) => { ... })

Ref獲取子組件Dom元素或是React元素的ref例子

高階組件(HOC)是react中對組件邏輯進行重用的高級技術。但高階組件本身並不是React API。它只是一種模式,其實就是一個函數,且該函數接受一個組件作為參數,並返回一個新的組件。高階組件在React第三方庫中很常見,比如Redux的connect方法和react-router的withRouter()方法。

註意事項:

1、不要再render函數中使用高階組件,不然會導致每次重新渲染,都會重新創建高階組件實例,銷毀掉舊的高階組件,導致所有狀態和子組件都被卸載。

2、必須將靜態方法做拷貝,當使用高階組件包裝組件,原始組件被容器組件包裹,得到新組件會丟失原始組件的所有靜態方法,假如原始組件有靜態方法,可以使用hoist-non-react-statics進行靜態方法拷貝。例子

3、Refs屬性不能傳遞,高階組件可以傳遞所有的props屬性給包裹的組件,但是不能傳遞refs引用,但是有時候我們確實需要把ref的引用傳給包裹組件,可以傳一個非ref命名的props屬性給到高階組件上,由高階組件綁定到包裹組件的ref上,也可以使用轉發Ref。例子

三、React第三方庫

1、Reduxreact-redux

Redux主要分成三部分,分別為Store,Action,Reducer,下麵是對三部分的通俗的講解:

Store:Redux應用只有一個單一的Store,就是單一數據源,將整個應用共用的狀態state儲存在一棵對象樹上面,註意的是,對象樹上面的state是只讀的,只能通過純函數來執行修改,創建store,是通過Redux的 createStore(reducer)方法來創建的,store裡面會有getState()、dispatch()、subscribe(listener)的方法。

Action:一個普通的Javascript對象,描述了應用state發生了什麼變化,通過dispatch方法來通知store調用reducer方法。

Reducer:描述應用如何更新state,本身是一個函數,接受Action參數,返回新的state。

不結合react-redux的Redux使用例子

需要明白的一點Redux跟React一點關係都沒有,但是React搭配Redux來實現狀態管理時最好的實現方案。那麼如何搭配呢?本來我們可以subscribe(listener)在react的組件註冊redux的監聽器,但是這種方式繁瑣,而且會導致多次渲染。所以搭配著react-redux來使用。基本使用如下:

import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
import App from './components/App'

const todoApp = (state = {}, action) {
   if (actions.type === 'SHOW') {
       return Object.assign({}, state, {
        show: action.show
       });
   }
   return state;
}

let store = createStore(todoApp)
render(
  // 使用指定的 React Redux 組件 <Provider> 來讓所有容器組件都可以訪問 store,而不必顯示地傳遞它。只需要在渲染根組件時使用即可。
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)
import React from 'react'
import { connect } from 'react-redux';
import Child from './components/Child'
class App extends Component {
    render() {
        const { show } = this.props;
        return (
            <div>
                <Child show={show }/>
            </div>
        );
    }
}
const stateToProps = (state) => ({
    show: state.show
});

export default connect(stateToProps)(App);

結合react-redux的例子

react-redux內容實現原理,使用的Context API,簡單來說,父組件聲明需要跨層級組件傳遞的屬性(childContextType)以及監聽屬性變化的getChildContext()函數,子組件聲明可以接收上層組件傳遞的屬性(contextType)。

如果存在多個reducer的話,可以使用redux中的combineReducers進行合併,代碼如下:

import { createStore, combineReducers } from 'redux';
const todoApp = combineReducers({
  reducer1,
  reducer2
})
const store = createStore(todoApp);

代碼等價於:

import { createStore} from 'redux';
const todoApp = (state = {}, action) => {
  return {
    reducer1: state.reducer1,
    reducer2: state.reducer2
  }
}
const store = createStore(todoApp);

combineReducers最終只是生成一個函數,這個函數來調用你的一系列 reducer,每個 reducer 根據它們的 key 來篩選出 state 中的一部分數據並處理,然後這個生成的函數再將所有 reducer 的結果合併成一個大的對象。詳細邏輯可以看redux源碼

2、react-router

對於路由規則,我們在項目裡面搭配的是react-router v4這個庫來完成的,由於我們這之前也沒接觸過react-router,所以版本v3與v4之間模式和策略的差異不同也沒有帶來思維模式轉換的困難,下麵先帖碼簡單看看v3與v4版本之間的差異性(摘自掘金):

import { Router, Route, IndexRoute } from 'react-router'
const PrimaryLayout = props => (
    <div className="primary-layout">
        <header>
          Our React Router 3 App
        </header>
        <main>
          {props.children}
        </main>
  </div>
)
const HomePage =() => <div>Home Page</div>
const UsersPage = () => <div>Users Page</div>
const App = () => (
  <Router history={browserHistory}>
    <Route path="/" component={PrimaryLayout}>
      <IndexRoute component={HomePage} />
      <Route path="/users" component={UsersPage} />
    </Route>
  </Router>
)
render(<App />, document.getElementById('root'))
import { BrowserRouter, Route } from 'react-router-dom'

const PrimaryLayout = () => (
    <div className="primary-layout">
    <header>
      Our React Router 4 App
    </header>
    <main>
      <Route path="/" exact component={HomePage} />
      <Route path="/users" component={UsersPage} />
    </main>
  </div>
)

const HomePage =() => 
<div>Home Page</div>

const UsersPage = () => 
<div>Users Page</div>


const App = () => (
  <BrowserRouter>
    <PrimaryLayout />
  </BrowserRouter>
)

render(<App />, document.getElementById('root'))

差異性:

1、v3是集中性路由,所有路由都是集中在一個地方, 而v4則相反。

2、v3佈局和頁面嵌套是通過 組件的嵌套而來的,而v4不會互相嵌套

3、v3佈局和頁面組件是完全純粹的,它們是路由的一部分,而v4路由規則位於佈局和 UI 本身之間

4、使用v4需要在我們的組件根部用BrowserRouter組件(用於瀏覽器)去包裝,實現原理與react-redux的Provider組件一樣(Context API),以便組件可以去拿到路由信息。

這裡主要介紹包容性路由、排他性路由、嵌套路由,以及withRouter的一些基本用法。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 最近學習css發現了高度塌陷時候要清除浮動,為了理解清楚浮動原理,網上找了不少資料,發現都寫的不是很清楚,而且都是一模一樣的內容,我在里分享一下我對清楚浮動原理的理解, 如果你已經很瞭解什麼是浮動和浮動的效果你可以直接跳轉到三.如何清除浮動(重點)閱讀 一.什麼是浮動首先我們需要知道定位 元素在頁面 ...
  • 以前只使用django和jquery做小項目開發,所以決定搞一搞react框架。React 特點:聲明式設計、虛擬DOM、JSX、組件、數據驅動。 一、環境搭建 1.安裝npm、cnpm 2.安裝react全家桶 3.文件目錄結構 項目啟動時,會載入public下的index.html文件,併進而執 ...
  • 昨天寫了個小爬蟲,用axios.all同時請求多個頁面時,國內網路的原因很容易就超時然後reject了,佛系resolve不可取啊,然後想到可以實現一個“重發失敗請求”的功能。 Promise.all(requestPromises).then(...).catch(...) 會在所有request ...
  • 項目中遇到一個時間插件的BUG,查看源碼之後發現是因為setMonth()的問題,使用了之後會某些月份會出現月份加一的問題, 查閱資料後發現 setMonth()其實是設置與當前時間天數相同的月份,如果設置的月份與當前天數不相同則往後順延一個月 而w3c上只是簡單說明這個的作用 想必插件的作者對於這 ...
  • 1.坑爹的jquery ui datepicker 竟然不支持選取時分秒,害的我Format半天 期間嘗試了bootstrap的ditepicker,但是不起作用,發現被jquery ui 覆蓋了, 2.解決方案 下載jquery-ui-timepicker-addon.js,地址:http://j ...
  • import React, {Component} from 'react'; import { NavLink,Link } from "react-router-dom"; import './index.less'; import PropTypes from 'prop-types'; //... ...
  • 備註:我們經常會遇到使用jquery獲取某個地址下的部分頁面內容,然後替換當前頁面對應內容,也就是:局部刷新功能。 當然也可以使用get/post請求獲取數據,修改數據,可以參考以下JS代碼: ...
  • 一、安裝SubLime Text 3SubLime Text 3官網下載:https://www.sublimetext.com/ 二、安裝Package Control進入sublime後,按快捷鍵Ctrl+、鍵,進入命令行模式,sublime text 3在命令行輸入: sublime text ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...