日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

探秘react,一文弄懂react的基本使用和高级特性

發布時間:2023/12/4 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 探秘react,一文弄懂react的基本使用和高级特性 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一文詳解react的基本使用、高級特性和周邊插件

  • ?序言
  • 📝一、React的基本使用
    • 1、JSX基本使用
      • (1)變量、表達式
      • (2)class和style
      • (3)子元素和組件
      • (4)原生 html
    • 2、條件判斷
      • (1)if else
      • (2)三元表達式
      • (3)邏輯運算符 && ||
    • 3、渲染列表
      • (1)map 和 key
    • 4、React的事件
      • (1)bind this
      • (2)關于 event 參數
      • (3)傳遞自定義參數
      • (4)注意點
    • 5、表單
      • (1)受控組件
      • (2)input textarea select 用value
      • (3)checkbox radio 用 checked
    • 6、組件使用
      • (1)props 傳遞數據
      • (2)props 傳遞函數
      • (3)props 類型檢查
    • 7、setState
      • (1)不可變值
      • (2)可能是異步更新
      • (3)可能會被合并
    • 8、組件生命周期
  • 📖二、React高級特性
    • 1、函數組件
    • 2、非受控組件
      • (1)input
      • (2)checkbox
      • (3)file
      • (4)總結梳理
    • 3、Protals
      • (1)為什么要用 Protals ?
      • (2)如何使用
      • (3)使用場景
    • 4、context
      • (1)使用場景
      • (2)舉例闡述
    • 5、異步組件(懶加載)
    • 6、性能優化
      • (1)shouldComponentUpdate(簡稱SCU)
      • (2)PureComponent和React.memo
      • (3)不可變值
    • 7、關于組件公共邏輯的抽離
      • (1)高階組件 HOC
      • (2)Render Props
      • (3)HOC vs Render Props
  • 📚三、Redux和React-router
    • 1、Redux
      • (1)Redux概念簡述
      • (2)Redux的工作流程
      • (2)react-redux
      • (3)異步action
      • (4)Redux數據流圖
    • 2、React-router
      • (1)路由模式
      • (2)路由配置
        • Ⅰ. 動態路由
        • Ⅱ. 懶加載
  • 🗞?四、結束語

?序言

對于剛學習 react 的小伙伴來說,總是從基礎開始學習,周一自然也不例外捏。那在下面的文章中,將講解 react 的基本使用和高級特性,更有周邊插件 Redux 和 React-router 待你來探尋。

在本文中,融合大量案例🌰和動圖🕹?進行展示。可以把它當成是 react 的入門寶庫,有不懂的語法知識點時或許在這里可以尋找到你的答案并且通過例子運用起來。

叮,廢話不多說,下面來開始探索 react 的奧秘吧👏

📝一、React的基本使用

1、JSX基本使用

(1)變量、表達式

在 react 中,最基礎的內容便是變量和表達式,具體形式如下:

第一種類型:獲取變量、插值

import React from 'react'class JSXBaseDemo extends React.Component {constructor(props) {super(props)this.state = {name: '掘金:星期一研究室',imgUrl: 'https://p3-passport.byteacctimg.com/img/user-avatar/cc88f43a329099d65898aff670ea1171~300x300.image',flag: true}}render() {// 獲取變量 插值const pElem = <p>{this.state.name}</p>return pElem} }export default JSXBaseDemo

注意, react 中插值的形式是單個花括號 {} 的形式。最終瀏覽器顯示的效果如下:

第二種類型:表達式

import React from 'react'class JSXBaseDemo extends React.Component {constructor(props) {super(props)this.state = {name: '掘金:星期一研究室',imgUrl: 'https://p3-passport.byteacctimg.com/img/user-avatar/cc88f43a329099d65898aff670ea1171~300x300.image',flag: true}}render() {// 表達式const exprElem = <p>{this.state.flag ? 'yes' : 'no'}</p>return exprElem} }export default JSXBaseDemo

react 中也支持直接在插值里面使用表達式,如上述代碼中的 this.state.flag ? 'yes' : 'no' 。最終瀏覽器的顯示效果如下:

(2)class和style

通常情況下,如果我們要給某一個標簽設置類名,那么會給該標簽加上一個 class 。而在 react 中,如果想要給一個標簽加上一個類,那么需要給其加上 className 。具體代碼如下:

import React from 'react' import './style.css' import List from '../List'class JSXBaseDemo extends React.Component {render() {// classconst classElem = <p className="title">設置 css class</p>// styleconst styleData = { fontSize: '30px', color: 'blue' }const styleElem1 = <p style={styleData}>設置 style</p>// 內聯寫法,注意 {{ 和 }}const styleElem2 = <p style={{ fontSize: '30px', color: 'blue' }}>設置 style</p>// 返回結果return [ classElem, styleElem1, styleElem2 ]} }export default JSXBaseDemo

此時瀏覽器的顯示效果為:

同時需要注意的是,在 react 中,如果要在標簽里面寫內聯樣式,那么需要使用雙花括號 {{}} 來表示。

(3)子元素和組件

第一種類型:子元素

對于子元素來說,它可以在標簽里面進行使用。如下代碼所示:

import React from 'react'class JSXBaseDemo extends React.Component {constructor(props) {super(props)this.state = {name: '掘金:星期一研究室',imgUrl: 'https://p3-passport.byteacctimg.com/img/user-avatar/cc88f43a329099d65898aff670ea1171~300x300.image',flag: true}}render() {// 子元素const imgElem = <div><p>我的頭像</p><img src="xxxx.png"/><img src={this.state.imgUrl}/></div>return imgElem} }export default JSXBaseDemo

最終,瀏覽器的顯示效果為:

第二種類型:加載組件

如果要在 React 中加載一個組件,那么我們可以這么處理。具體代碼如下:

import React from 'react' import './style.css' import List from '../List'class JSXBaseDemo extends React.Component {constructor(props) {super(props)this.state = {name: '掘金:星期一研究室',imgUrl: 'https://p3-passport.byteacctimg.com/img/user-avatar/cc88f43a329099d65898aff670ea1171~300x300.image',flag: true}}render() {// 加載組件const componentElem = <div><p>JSX 中加載一個組件</p><hr/><List/></div>return componentElem} }export default JSXBaseDemo

List.js 組件的代碼如下:

import React from 'react'class List extends React.Component {constructor(props) {super(props)this.state = {name: 'React',list: ['a', 'b', 'c']}}render() {return <div><p onClick={this.changeName.bind(this)}>{this.state.name}</p><ul>{this.state.list.map((item, index) => {return <li key={index}>{item}</li>})}</ul><button onClick={this.addItem.bind(this)}>添加一項</button></div>}changeName() {this.setState({name: '星期一研究室'})}addItem() {this.setState({list: this.state.list.concat(`${Date.now()}`) // 使用不可變值})} }export default List

此時瀏覽器的顯示效果如下:

由此,我們就將一個組件注入到組件當中。

(4)原生 html

繼續,我們來看原生 html 在 react 中是如何使用的。先看以下代碼:

import React from 'react'class JSXBaseDemo extends React.Component {render() {// 原生 htmlconst rawHtml = '<span>富文本內容<i>斜體</i><b>加粗</b></span>'const rawHtmlData = {// 把 rawHtml 賦值給 __html__html: rawHtml // 注意,必須是這種格式}const rawHtmlElem = <div><p dangerouslySetInnerHTML={rawHtmlData}></p><p>{rawHtml}</p></div>return rawHtmlElem} }export default JSXBaseDemo

此時瀏覽器的顯示效果如下:

大家可以看到,如果要在 react 中使用原生 html ,那么必須使用 const rawHtmlData = { __html: rawHtml } 這種形式,才能將原生 html 代碼給解析出來。否則的話, react 是無法正常將原生 html 解析出來的。

2、條件判斷

(1)if else

先看下面這段代碼:

import React from 'react' import './style.css'class ConditionDemo extends React.Component {constructor(props) {super(props)this.state = {theme: 'black'}}render() {const blackBtn = <button className="btn-black">black btn</button>const whiteBtn = <button className="btn-white">white btn</button>// if elseif (this.state.theme === 'black') {return blackBtn} else {return whiteBtn}} }export default ConditionDemo

style.css 的代碼如下:

.title {font-size: 30px;color: red; }.btn-white {color: #333; } .btn-black {background-color: #666;color: #fff;; }

此時瀏覽器的顯示效果為:

大家可以看到,當我們 theme 設置為 black 時,最終顯示的效果就是黑色。如果我們把 theme 設置為其他狀態,那么最終顯示的效果就是白色

(2)三元表達式

先來看一段代碼:

import React from 'react' import './style.css'class ConditionDemo extends React.Component {constructor(props) {super(props)this.state = {theme: 'black'}}render() {const blackBtn = <button className="btn-black">black btn</button>const whiteBtn = <button className="btn-white">white btn</button>// 三元運算符return <div>{ this.state.theme === 'black' ? blackBtn : whiteBtn }</div>} }export default ConditionDemo

此時瀏覽器的顯示效果為:

大家可以看到,我們也可以通過三元表達式 this.state.theme === 'black' ? blackBtn : whiteBtn 的方式來對一些條件進行判斷。

(3)邏輯運算符 && ||

先來看一段代碼:

import React from 'react' import './style.css'class ConditionDemo extends React.Component {constructor(props) {super(props)this.state = {theme: 'black'}}render() {const blackBtn = <button className="btn-black">black btn</button>const whiteBtn = <button className="btn-white">white btn</button>// &&return <div>{ this.state.theme === 'black' && blackBtn }</div>} }export default ConditionDemo

此時瀏覽器的顯示結果也是和上述一樣的。具體如下:

this.state.theme === 'black' && blackBtn 這句話的意思為,如果 this.state.theme 的值為 black 時,那么返回 backBtn 的結果。

3、渲染列表

(1)map 和 key

先來看一段代碼:

import React from 'react'class ListDemo extends React.Component {constructor(props) {super(props)this.state = {list: [{id: 'id-1',title: '標題1'},{id: 'id-2',title: '標題2'},{id: 'id-3',title: '標題3'}]}}render() {return <ul>{ /* 類似于vue中的v-for */this.state.list.map((item, index) => {// 這里的 key 和 Vue 的 key 類似,必填,不能是 index 或 randomreturn <li key={item.id}>index {index}; id {item.id}; title {item.title}</li>})}</ul>} }export default ListDemo

此時瀏覽器的顯示效果如下:

在 react 中,使用的是 list.map 來渲染列表。其中, 需要注意的是, list.map() 是一個函數,那現在我們假設這個函數里面要遵循一套規則 list.map( item => item.id ) 。

這個時候,我們視 .map 為一個數組的重組,那么重組的規則就是 item => item.id 。同時, list.map 返回的是一個數組

4、React的事件

(1)bind this

先來看一段代碼:

import React from 'react'class EventDemo extends React.Component {constructor(props) {super(props)this.state = {name: 'zhangsan'}// 修改方法的 this 指向// 使用這個寫法,組件初始化時,只執行一次bindthis.clickHandler1 = this.clickHandler1.bind(this)}render() {// this - 使用 bindreturn <p onClick={this.clickHandler1}>{this.state.name}</p>}clickHandler1() {// console.log('this....', this) // this 默認是 undefinedthis.setState({name: 'lisi'})} }export default EventDemo

最終瀏覽器顯示的效果為:

在這段代碼中,我們通過 this.clickHandler1 = this.clickHandler1.bind(this) 來對 clickHandler1 進行綁定。


還有另外一種關于 this 的綁定方法。先來看一段代碼:

import React from 'react'class EventDemo extends React.Component {constructor(props) {super(props)this.state = {name: 'zhangsan'}}render() {// this - 使用靜態方法return <p onClick={this.clickHandler2}>clickHandler2 {this.state.name}</p>}// 靜態方法,this 指向當前實例clickHandler2 = () => {this.setState({name: 'lisi'})} }export default EventDemo

此時瀏覽器的顯示效果為:

對于上面的這種方式來說, clickHandler2 是一個靜態方法,此時它的 this 會指向當前的實例。

(2)關于 event 參數

先來看一段代碼:

import React from 'react'class EventDemo extends React.Component {constructor(props) {super(props)this.state = {name: 'zhangsan'}}render() {// eventreturn <a href="https://imooc.com/" onClick={this.clickHandler3}>click me</a>}// 獲取 event (重點)clickHandler3 = (event) => {event.preventDefault() // 阻止默認行為event.stopPropagation() // 阻止冒泡console.log('target', event.target) // 指向當前元素,即當前元素觸發console.log('current target', event.currentTarget) // 指向當前元素,假象!!!// 注意,event 其實是 React 封裝的。可以把 __proto__.constructor 看成是 SyntheticEvent 組合事件console.log('event', event) // 不是原生的 Event ,原生的是 MouseEventconsole.log('event.__proto__.constructor', event.__proto__.constructor)// 原生 event 如下。其 __proto__.constructor 是 MouseEventconsole.log('nativeEvent', event.nativeEvent)console.log('nativeEvent target', event.nativeEvent.target) // 指向當前元素,即當前元素觸發console.log('nativeEvent current target', event.nativeEvent.currentTarget) // 指向 document !!!} }export default EventDemo

此時瀏覽器的顯示效果如下:

依據以上內容,需要注意的點是:

  • event 是合成事件 SyntheticEvent ,它能夠模擬出來 DOM 事件所有的能力;
  • event 是React 封裝出來的,而 event.nativeEvent 是原生事件對象;
  • 所有的事件,都會被掛載到 document 上;
  • React 中的事件,和 DOM 事件不一樣,和 Vue 事件也不一樣。

(3)傳遞自定義參數

先來看一段代碼:

import React from 'react'class EventDemo extends React.Component {constructor(props) {super(props)this.state = {name: 'zhangsan',list: [{id: 'id-1',title: '標題1'},{id: 'id-2',title: '標題2'},{id: 'id-3',title: '標題3'}]}}render() {// 傳遞參數 - 用 bind(this, a, b)return <ul>{this.state.list.map((item, index) => {return <li key={item.id} onClick={this.clickHandler4.bind(this, item.id, item.title)}>index {index}; title {item.title}</li>})}</ul>}// 傳遞參數clickHandler4(id, title, event) {console.log(id, title)console.log('event', event) // 最后追加一個參數,即可接收 event} }export default EventDemo

此時,瀏覽器的顯示效果為:

大家可以看到,我們通過使用 this.clickHandler4.bind(this, item.id, item.title) 這種形式來對 react 中的事件進行參數傳遞。

(4)注意點

  • React 16 將事件綁定到 document 上;
  • React 17 將事件綁定到 root 組件上;
  • 這樣做的好處在于:有利于多個 React 版本并存,例如微前端

如下圖所示:

5、表單

(1)受控組件

先來看一段代碼:

import React from 'react'class FormDemo extends React.Component {constructor(props) {super(props)this.state = {name: '星期一研究室',info: '個人信息',city: 'GuangDong',flag: true,gender: 'female'}}render() {// 受控組件return <div><p>{this.state.name}</p><label htmlFor="inputName">姓名:</label> {/* 用 htmlFor 代替 for */}<input id="inputName" value={this.state.name} onChange={this.onInputChange}/></div>}onInputChange = (e) => {this.setState({name: e.target.value})} }export default FormDemo

此時瀏覽器的顯示效果如下:

在 react 中,通過使用 onChange 事件來手動修改 state 里面的值。

(2)input textarea select 用value

上面我們已經講解了 input ,接下來我們來看 textarea 和 select 。

先來看 textarea 相關的代碼:

import React from 'react'class FormDemo extends React.Component {constructor(props) {super(props)this.state = {name: '星期一研究室',info: '個人信息',city: 'GuangDong',flag: true,gender: 'female'}}render() {// textarea - 使用 valuereturn <div><textarea value={this.state.info} onChange={this.onTextareaChange}/><p>{this.state.info}</p></div>}onTextareaChange = (e) => {this.setState({info: e.target.value})} }export default FormDemo

此時瀏覽器的打印效果是:

同樣地, textarea 也是用 value 和 onChange 來對進行綁定。


繼續來看 select 。具體代碼如下:

import React from 'react'class FormDemo extends React.Component {constructor(props) {super(props)this.state = {name: '星期一研究室',info: '個人信息',city: 'GuangDong',flag: true,gender: 'female'}}render() {// textarea - 使用 valuereturn <div><textarea value={this.state.info} onChange={this.onTextareaChange}/><p>{this.state.info}</p></div>}onSelectChange = (e) => {this.setState({city: e.target.value})} }export default FormDemo

此時,瀏覽器的顯示效果為:

與 input 和 textarea 一樣,也是通過操作 value 和 onChange ,來改變最終的值。

(3)checkbox radio 用 checked

先來看 ckeckbox 。代碼如下:

import React from 'react'class FormDemo extends React.Component {constructor(props) {super(props)this.state = {name: '星期一研究室',info: '個人信息',city: 'GuangDong',flag: true,gender: 'female'}}render() {// checkboxreturn <div><input type="checkbox" checked={this.state.flag} onChange={this.onCheckboxChange}/><p>{this.state.flag.toString()}</p></div>}onCheckboxChange = () => {this.setState({flag: !this.state.flag})} }export default FormDemo

此時瀏覽器的顯示效果為:

在上面的代碼中, checkbox 通過操作 checked 和 onChange ,來改變 state 的值。


radio 也是類似,如下代碼所示:

import React from 'react'class FormDemo extends React.Component {constructor(props) {super(props)this.state = {name: '星期一研究室',info: '個人信息',city: 'GuangDong',flag: true,gender: 'female'}}render() {// radioreturn <div>male <input type="radio" name="gender" value="male" checked={this.state.gender === 'male'} onChange={this.onRadioChange}/>female <input type="radio" name="gender" value="female" checked={this.state.gender === 'female'} onChange={this.onRadioChange}/><p>{this.state.gender}</p></div>}onRadioChange = (e) => {this.setState({gender: e.target.value})} }export default FormDemo

此時瀏覽器的顯示效果是:

6、組件使用

對于父子組件的使用來說,我們需要明白三個知識點:props 傳遞數據、props 傳遞函數和 props 類型檢查。

先來看一段代碼:

import React from 'react' import PropTypes from 'prop-types'class Input extends React.Component {constructor(props) {super(props)this.state = {title: ''}}render() {return <div><input value={this.state.title} onChange={this.onTitleChange}/><button onClick={this.onSubmit}>提交</button></div>}onTitleChange = (e) => {this.setState({title: e.target.value})}onSubmit = () => {const { submitTitle } = this.propssubmitTitle(this.state.title)this.setState({title: ''})} } // props 類型檢查 Input.propTypes = {submitTitle: PropTypes.func.isRequired }class List extends React.Component {constructor(props) {super(props)}render() {const { list } = this.propsreturn <ul>{list.map((item, index) => {return <li key={item.id}><span>{item.title}</span></li>})}</ul>} } // props 類型檢查 // 通過propTypes可以清楚地知道list需要一個什么類型的數據 List.propTypes = {list: PropTypes.arrayOf(PropTypes.object).isRequired }class Footer extends React.Component {constructor(props) {super(props)}render() {return <p>{this.props.text}{this.props.length}</p>}componentDidUpdate() {console.log('footer did update')}shouldComponentUpdate(nextProps, nextState) {if (nextProps.text !== this.props.text|| nextProps.length !== this.props.length) {return true // 可以渲染}return false // 不重復渲染}// React 默認:父組件有更新,子組件則無條件也更新!!!// 性能優化對于 React 更加重要!// SCU 一定要每次都用嗎?—— 需要的時候才優化(SCU即shouldComponentUpdate) }// 父組件 class TodoListDemo extends React.Component {constructor(props) {super(props)// 狀態(數據)提升// list的數據需要放在父組件this.state = {list: [{id: 'id-1',title: '標題1'},{id: 'id-2',title: '標題2'},{id: 'id-3',title: '標題3'}],footerInfo: '底部文字'}}render() {return <div><Input submitTitle={this.onSubmitTitle}/><List list={this.state.list}/><Footer text={this.state.footerInfo} length={this.state.list.length}/></div>}onSubmitTitle = (title) => {this.setState({list: this.state.list.concat({id: `id-${Date.now()}`,title})})} }export default TodoListDemo

此時瀏覽器的顯示效果如下:

依據以上代碼,我們來對 props 的各個類型進行介紹。

(1)props 傳遞數據

最后一個 TodoListDemo 是父組件,其他都是子組件。在 Input 組件和 List 組件中,我們將 props 屬性的內容,以 this.props.xxx 的方式,傳遞給父組件

(2)props 傳遞函數

React 在傳遞函數這一部分和 vue 是不一樣的。對于 vue 來說,如果有一個父組件要傳遞函數給子組件,子組件如果想要觸發這個函數,那么需要使用事件傳遞和 $emit 的方式來解決。

大家定位到 Input 組件中,在這里,我們將 submitTitle 以函數的形式,傳遞給父組件中的 onSubmitTitle 。

(3)props 類型檢查

大家定位到兩處 props 類型檢查的地方。使用 react 中的 PropTypes ,我們可以對當前所使用的屬性進行一個類型檢查。比如說: submitTitle: PropTypes.func.isRequired 表明的是, submitTitle 是一個函數,并且是一個必填項。

就這樣,通過上面的例子,我們學習了屬性傳遞屬性驗證以及父組件和子組件之間怎么通過傳事件的形式來進行通信

7、setState

(1)不可變值

所謂不可變值,即所設置的值永不改變。那這個時候,我們就需要去創建一個副本,來設置 state 的值。

來看幾個要點:

第一點:state 要在構造函數中定義。如下代碼所示:

import React from 'react'// 函數組件,默認沒有 state class StateDemo extends React.Component {constructor(props) {super(props)// 第一,state 要在構造函數中定義this.state = {count: 0}}render() {return <div><p>{this.state.count}</p></div>} }export default StateDemo

第二點,不要直接修改 state ,要使用不可變值。如下代碼所示:

import React from 'react'// 函數組件,默認沒有 state class StateDemo extends React.Component {constructor(props) {super(props)// 第一,state 要在構造函數中定義this.state = {count: 0}}render() {return <div><p>{this.state.count}</p><button onClick={this.increase}>累加</button></div>}increase= () => {// 第二,不要直接修改 state,使用不可變值// this.state.count++ // 錯誤寫法,會直接修改原來的值this.setState({count: this.state.count + 1 // ShouldComponentUpdate → SCU})} }export default StateDemo

大家可以看到,在上面的代碼中,我們通過 this.state({}) 這種形式,來修改 state 的值。值得注意的是,很多小伙伴會直接使用 this.state.count++ 來修改 state 的值,這在 react 中是非常不允許的。因此,要注意這個要點。

第三點,在 react 中操作數組的值。如下代碼所示:

// 不可變值(函數式編程,純函數) - 數組 const list5Copy = this.state.list5.slice() list5Copy.splice(2, 0, 'a') // 中間插入/刪除 this.setState({list1: this.state.list1.concat(100), // 追加list2: [...this.state.list2, 100], // 追加list3: this.state.list3.slice(0, 3), // 截取list4: this.state.list4.filter(item => item > 100), // 篩選list5: list5Copy // 其他操作 }) // 注意,不能直接對 this.state.list 進行 push pop splice 等,這樣違反不可變值

第四點,在 react 中操作對象的值。如下代碼所示:

// 不可變值 - 對象 this.setState({obj1: Object.assign({}, this.state.obj1, {a: 100}),obj2: {...this.state.obj2, a: 100} }) // 注意,不能直接對 this.state.obj 進行屬性設置,即 this.state.obj.xxx 這樣的形式,這種形式會違反不可變值

(2)可能是異步更新

react 中的 state ,有可能是異步更新。來看一段代碼:

import React from 'react'class StateDemo extends React.Component {constructor(props) {super(props)this.state = {count: 0}}render() {return <div><p>{this.state.count}</p><button onClick={this.increase}>累加</button></div>}increase= () => {// setState 可能是異步更新(也有可能是同步更新) this.setState({count: this.state.count + 1}, () => {// 聯想 Vue $nextTick - DOMconsole.log('count by callback', this.state.count) // 回調函數中可以拿到最新的 state})console.log('count', this.state.count) // 異步的,拿不到最新值} }export default StateDemo

此時瀏覽器的顯示效果為:

大家可以看到,this.state 前半部分并不能同一時間得到更新,所以它是異步操作。而后面的箭頭函數中的內容可以得到同步更新,所以后面函數的部分是同步操作


值得注意的是, setTimeout 在 setState 中是同步的來看一段代碼:

import React from 'react'class StateDemo extends React.Component {constructor(props) {super(props)this.state = {count: 0}}render() {return <div><p>{this.state.count}</p><button onClick={this.increase}>累加</button></div>}increase= () => {// setTimeout 中 setState 是同步的setTimeout(() => {this.setState({count: this.state.count + 1})console.log('count in setTimeout', this.state.count)}, 0)} }export default StateDemo

此時,瀏覽器的顯示效果為:


還有一個要注意的點是,如果是自己定義的 DOM 事件,那么在 setState 中是同步的,用在 componentDidMount 中。

如果是銷毀事件,那么用在 componentWillMount 生命周期中。代碼如下:

import React from 'react'class StateDemo extends React.Component {constructor(props) {super(props)this.state = {count: 0}}render() {return <div><p>{this.state.count}</p><button onClick={this.increase}>累加</button></div>}bodyClickHandler = () => {this.setState({count: this.state.count + 1})console.log('count in body event', this.state.count)}componentDidMount() {// 自己定義的 DOM 事件,setState 是同步的document.body.addEventListener('click', this.bodyClickHandler)}componentWillUnmount() {// 及時銷毀自定義 DOM 事件document.body.removeEventListener('click', this.bodyClickHandler)// clearTimeout} }export default StateDemo

此時瀏覽器的顯示效果為:

(3)可能會被合并

setState 在傳入對象時,更新前會被合并。來看一段代碼:

import React from 'react'class StateDemo extends React.Component {constructor(props) {super(props)this.state = {count: 0}}render() {return <div><p>{this.state.count}</p><button onClick={this.increase}>累加</button></div>}increase= () => {// 傳入對象,會被合并(類似 Object.assign )。執行結果只一次 +1this.setState({count: this.state.count + 1})this.setState({count: this.state.count + 1})this.setState({count: this.state.count + 1})} }export default StateDemo

此時瀏覽器的顯示效果為:

有小伙伴可能會覺得,一下子多個三個 setState ,那結果應該是 +3 才是。但其實,如果傳入的是對象,那么結果會把三個合并為一個,最終只執行一次


還有另外一種情況,如果傳入的是數,那么結果不會被合并。來看一段代碼:

import React from 'react'class StateDemo extends React.Component {constructor(props) {super(props)this.state = {count: 0}}render() {return <div><p>{this.state.count}</p><button onClick={this.increase}>累加</button></div>}increase= () => {// 傳入函數,不會被合并。執行結果是 +3this.setState((prevState, props) => {return {count: prevState.count + 1}})this.setState((prevState, props) => {return {count: prevState.count + 1}})this.setState((prevState, props) => {return {count: prevState.count + 1}})} }export default StateDemo

此時瀏覽器的顯示效果為:

大家可以看到,如果傳入的是函數,那么結果一下子就執行三次了。

8、組件生命周期

react 的組件生命周期,有單組件聲明周期父子組件聲明周期。其中,父子組件生命周期與 Vue 類似。

這里附上一個生命周期相關的網站:https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/

下面附上生命周期的圖:

📖二、React高級特性

1、函數組件

我們先來了解 class 組件和函數組件分別是什么樣的。先看 class 組件,代碼如下:

// class 組件 class List extends React.Component {constructor(props) {super(props)}redner() {const { list } = this.propsreturn <ul>{list.map((item, index) => {return <li key={item.id}><span>{item.title}</span></li>})}</ul>} }

函數組件的形式如下:

// 函數組件 function List(props) {const { list } = this.propsreturn <ul>{list.map((item, idnex) => {return <li key={item.id}><span>{item.title}</span></li>})}</ul> }

現在我們來梳理以下, class 組件和函數組件兩者之間的區別。所謂函數組件,具有以下特點:

  • 只是一個純函數,它輸入的是 props ,輸出的是 JSX ;
  • 函數組件沒有實例沒有生命周期,也沒有 state
  • 函數組件不能擴展其他方法

相反地, class 組件就擁有函數組件相異的特點。

2、非受控組件

在上述表單模塊,我們談論到了受控組件,那接下來,我們就來談論非受控組件

所謂非受控組件,就是 input 里面的值,不受到 state 的控制。下面我們先來看幾種場景。

(1)input

先來看一段代碼:

import React from 'react'class App extends React.Component {constructor(props) {super(props)this.state = {name: '星期一研究室',flag: true,}this.nameInputRef = React.createRef() // 創建 ref}render() {// input defaultValuereturn <div>{/* 使用 defaultValue 而不是 value ,使用 ref */}<input defaultValue={this.state.name} ref={this.nameInputRef}/>{/* state 并不會隨著改變 */}<span>state.name: {this.state.name}</span><br/><button onClick={this.alertName}>alert name</button></div>}alertName = () => {const elem = this.nameInputRef.current // 通過 ref 獲取 DOM 節點alert(elem.value) // 不是 this.state.name} }export default App

此時瀏覽器的顯示效果為:

大家可以看到,如果是非受控組件,那么需要使用 defaultValue 去控制組件的值。且最終 input 框里面的內容不論我們怎么改變,都不會影響到 state 的值。

(2)checkbox

對于復選框 checkbox 來說,先看以下代碼:

import React from 'react'class App extends React.Component {constructor(props) {super(props)this.state = {name: '星期一研究室',flag: true,}}render() {// checkbox defaultCheckedreturn <div><inputtype="checkbox"defaultChecked={this.state.flag}/><p>state.name: { this.state.flag === true ? 'true' : 'false' }</p></div>} }export default App

此時瀏覽器的顯示效果如下:

大家可以看到,復選框如果當非受控組件來使用的使用,那么使用 defaultCkecked 來對值進行控制。同時,我們也看到了,最終不管 checked 的值如何改變, state 的值都不受影響。

(3)file

先來看一段代碼:

import React from 'react'class App extends React.Component {constructor(props) {super(props)this.state = {name: '星期一研究室',flag: true,}this.fileInputRef = React.createRef()}render() {// filereturn <div><input type="file" ref={this.fileInputRef}/><button onClick={this.alertFile}>alert file</button></div>}alertFile = () => {const elem = this.fileInputRef.current // 通過 ref 獲取 DOM 節點alert(elem.files[0].name)} }export default App

此時瀏覽器的顯示效果為:

在上面的代碼中,我們使用通過 ref 去獲取 DOM 節點,接著去獲取到文件的名字。像 file 這種類型的固定,值并不會一直固定的,所以也是一個非受控組件

(4)總結梳理

setState 只能處理類似于前端的顯示和渲染相關的,像文件上傳這種交互類型的就處理不了。下面我們來梳理下非受控組件的幾大使用場景具體如下:

  • 必須手動操作 DOM 元素, setState 并無法手動操作 DOM 元素;
  • 文件上傳類型 <input type=file> ;
  • 某些富文本編輯器,需要傳入 DOM 元素。

受控組件 vs 非受控組件的區別如下:

  • 優先使用受控組件,符合 React 設計原則;
  • 必須操作 DOM 時,再使用非受控組件

3、Protals

(1)為什么要用 Protals ?

一般情況下,組件默認會按照既定層次嵌套渲染。類似下面這樣:

<div id="root"><div><div><div class="model">Modal內容</div></div></div> </div>

大家可以看到,這樣不斷嵌套,但里面卻只有一層區域的內容是有用的。從某種程度上來說,是非常不好的。那我們想做的事情是,如何讓組件渲染到父組件以外呢?

這個時候就需要用到 Protals 。

(2)如何使用

先來看一段代碼:

import React from 'react' import ReactDOM from 'react-dom' import './style.css'class App extends React.Component {constructor(props) {super(props)this.state = {}}render() {// 正常渲染// return <div className="modal">// {this.props.children} {/* vue slot */}// </div>// 使用 Portals 渲染到 body 上。// fixed 元素要放在 body 上,有更好的瀏覽器兼容性。return ReactDOM.createPortal(<div className="modal">{this.props.children}</div>,document.body // DOM 節點)} }export default App

style.css 代碼如下:

.modal {position: fixed;width: 300px;height: 100px;top: 100px;left: 50%;margin-left: -150px;background-color: #000;/* opacity: .2; */color: #fff;text-align: center; }

此時,我們來看下瀏覽器節點的渲染效果。具體如下:

大家可以看到,通過使用 ReactDOM.createPortal() ,來創建 Portals 。最終 modals 節點成功脫離開父組件,并渲染到組件外部。

(3)使用場景

現在,我們來梳理一些 Protals 常見的場景。

protals 常用于解決一些 css 兼容性問題。通常使用場景有:

  • overflow:hidden; 觸發 bfc ;
  • 父組件 z-index 值太小;
  • position:fixed 需要放在 body 第一層級。

4、context

(1)使用場景

有時候我們經常會有一些場景出現切換的頻率很頻繁,比如語言切換、或者是主題切換,那如何把對應的切換信息給有效地傳遞給每個組件呢?

使用 props ,又有點繁瑣;使用 redux ,又太小題大做了。

因此,這個需要我們可以用 react 中的 context 。

(2)舉例闡述

先來看一段代碼:

import React from 'react'// 創建 Context 填入默認值(任何一個 js 變量) const ThemeContext = React.createContext('light')// 底層組件 - 函數是組件 function ThemeLink (props) {// const theme = this.context // 會報錯。函數式組件沒有實例,即沒有 this// 函數式組件可以使用 Consumerreturn <ThemeContext.Consumer>{ value => <p>link's theme is {value}</p> }</ThemeContext.Consumer> }// 底層組件 - class 組件 class ThemedButton extends React.Component {// 指定 contextType 讀取當前的 theme context。// static contextType = ThemeContext // 也可以用 ThemedButton.contextType = ThemeContextrender() {const theme = this.context // React 會往上找到最近的 theme Provider,然后使用它的值。return <div><p>button's theme is {theme}</p></div>} } ThemedButton.contextType = ThemeContext // 指定 contextType 讀取當前的 theme context。// 中間的組件再也不必指明往下傳遞 theme 了。 function Toolbar(props) {return (<div><ThemedButton /><ThemeLink /></div>) }class App extends React.Component {constructor(props) {super(props)this.state = {theme: 'light'}}render() {return <ThemeContext.Provider value={this.state.theme}><Toolbar /><hr/><button onClick={this.changeTheme}>change theme</button></ThemeContext.Provider>}changeTheme = () => {this.setState({theme: this.state.theme === 'light' ? 'dark' : 'light'})} }export default App

此時瀏覽器的顯示效果為:

在上圖中,我們做到了主題的切換。現在,我們來分析下上述的代碼。

首先,我們創建了一個 Context ,也就是 ThemeContext ,并傳入了 light 值。

其次,核心在 <Toolbar /> 組件。 Toolbar 現有組件為 ThemedButton 和 ThemeLink 。其中,我們先指定 ThemedButton 的 contextType 去讀取當前的 ThemeContext ,那么就取到了默認值 light 。

接著,來到了 ThemeLink 組件。 ThemeLink 是一個函數式組件,因此,我們可以直接使用 ThemeContext.Consumer 來對其進行傳值。

上面兩個組件的值都取到了,但那只是 ThemeContext 的初始值。取到值了之后呢,我們還要修改值, React 會往上找到最近的 ThemeContext.Provider ,通過 value={this.state.theme} 這種方式,去修改和使用 ThemeContext 最終使用的值 。

5、異步組件(懶加載)

在項目開發時,我們總是會不可避免的去加載一些大組件,這個時候就需要用到異步加載。在 vue 中,我們通常使用 import() 來加載異步組件,但在 react 就不這么使用了。

React 通常使用 React.lazy 和 React.Suspense 來加載大組件。

如下代碼所示:

import React from 'react'const ContextDemo = React.lazy(() => import('./ContextDemo'))class App extends React.Component {constructor(props) {super(props)}render() {return <div><p>引入一個動態組件</p><hr /><React.Suspense fallback={<div>Loading...</div>}><ContextDemo/></React.Suspense></div>// 1. 強制刷新,可看到 loading (看不到就限制一下 chrome 的網速,Performance的network)// 2. 看 network 的 js 加載} }export default App

首先我們使用 import 去導入我們要加載的組件。之后使用 React.lazy 去將這個組件給進行注冊,也就是 ContextDemo 。最后使用 React.Suspense 來加載 ContextDemo 。至此,我們完成了該異步組件的加載。

6、性能優化

(1)shouldComponentUpdate(簡稱SCU)

先來看下面這一段代碼:

shouldComponentUpdate(nextProps, nextState) {if (nextState.count !== this.state.count|| nextProps.text !== this.props.length) {return true // 可以渲染}return false // 不重復渲染 }

在 React 中,默認的是,當父組件有更新,子組件也無條件更新。那如果每回都觸發更新,肯定不太好。

因此,這個時候我們需要用到 shouldComponentUpdate ,判斷當屬性有發生改變時,可以觸發渲染。當屬性不發生改變時,也就是前后兩次的值相同時,就不觸發渲染。

那這個時候我們 需要思考一個問題: SCU 一定要每次都用嗎?答案其實不是肯定的

我們會去用 SCU ,從某種層面上來講就是為了優化。因此,我們需要依據當前的開發場景,有需要的時候再去優化。

現在,我們來總結一下 SCU 的使用方式,具體如下:

  • SCU 默認返回 true ,即 React 默認重新渲染所有子組件;
  • 必須配合 “不可變值” 一起使用;
  • 可先不用 SCU ,有性能問題時再考慮使用。

(2)PureComponent和React.memo

PureComponent 在 react 中的使用形式如下:

class List extends React.PureComponent {constructor(props) {super(props)}render() {const { list } = this.propsreturn <ul>{list.map((item, index) => {return <li key={item.id}><span>{item.title}</span></li>})}</ul>}shouldComponentUpdate() {/*淺比較*/} }

如果我們使用了 PureComponent ,那么 SCU 會進行淺層比較,也就是一層一層的比較下去。


下面我們來看 memo 。 memo ,顧名思義是備忘錄的意思。在 React 中的使用形式如下:

function MyComponent(props) {/* 使用props 渲染 */ }function areEqual(prevProps, nextProps) {/*如果把 nextProps傳入render方法的返回結果 與preProps傳入render方法的返回結果 一致的話,則返回true,否則返回false*/ } export default React.memo(MyComponent, areEqual);

memo ,可以說是函數組件中的 PureComponent 。同時,使用 React.memo() 的形式,將我們的函數組件和 areEqual 的值進行比較,最后返回一個新的函數

值得注意的是,在 React 中,淺比較已經使用于大部分情況,一般情況下,盡量不要做深度比較

(3)不可變值

在 React 中,用于做不可變值的有一個庫: Immutable.js 。這個庫有以下幾大特點:

  • 徹底擁抱“不可變值”

  • 基于共享數據(不是深拷貝),速度好

  • 有一定的學習和遷移成本,按需使用

下面來看一個使用例子:

const map1 = Immutable.Map({ a: 1, b: 2, c: 3 }) const map2 = map1.set('b', 50) map1.get('b') // 2 map2.get('b') // 50

基本上現在在開發中都用這個庫來處理不可變值的問題。在實際使用中,可以看官方文檔按需使用即可。

7、關于組件公共邏輯的抽離

在 React 中,對于組件公共邏輯的抽離主要有三種方式要了解。具體如下:

  • mixin ,已被 React 棄用
  • 高階組件 HOC
  • Render Props

下面將講解高階組件 HOC 和 Render Props 。

(1)高階組件 HOC

先看一段代碼:

// 高階組件不是一種功能,而是一種設計模式 // 1.傳入一個組件 Component const HOCFactory = (Component) => {class HOC extends React.Component {// 在此定義多個組件的公共邏輯render() {// 2.返回拼接的結果return <Component {this.props} /> }}return HOC } const EnhancedComponent1 = HOCFactory(WrappedComponent1) const EnhancedComponent2 = HOCFactory(WrappedComponent2)

高階組件 HOC 是傳入一個組件,返回一個新的組件,見上方代碼的 1和2 。


下面來看一個例子,如下代碼所示:

import React from 'react'// 高階組件 const withMouse = (Component) => {class withMouseComponent extends React.Component {constructor(props) {super(props)this.state = { x: 0, y: 0 }}handleMouseMove = (event) => {this.setState({x: event.clientX,y: event.clientY})}render() {return (<div style={{ height: '500px' }} onMouseMove={this.handleMouseMove}>{/* 1. 透傳所有 props 2. 增加 mouse 屬性 */}<Component {...this.props} mouse={this.state}/></div>)}}return withMouseComponent }const App = (props) => {const { x, y } = props.mouse // 接收 mouse 屬性return (<div style={{ height: '500px' }}><h1>The mouse position is ({x}, {y})</h1></div>) }export default withMouse(App) // 返回高階函數

此時瀏覽器的顯示結果為:

在上面的代碼中,我們用 定義了高階組件 withMouse ,之后它通過 <Component {...this.props} mouse={this.state}/> 這種形式,將參數 propsprops 的 mouse 屬性給透傳出來,供子組件 App 使用。


值得注意的是,在 react 中,還有一個比較常見的高階組件是 redux connect 。用一段代碼來演示:

import { connect } from 'react-redux';// connect 是高階組件 const VisibleTodoList = connect(mapStateToProps,mapDispatchToProps )(TodoList)export default VisibleTodoList

現在,我們來看下 connect 的源碼,具體如下:

export const connect =(mapStateToProps, mapDispatchToProps) => (WrappedComponent) => {class Connect extends Component {constructor() {super()this.state = {allProps: {}}}/* 中間省略 N 行代碼 */render () {return <WrappedComponent {...this.state.allProps} />}}return Connect }

大家可以看到, Connect 也是同樣地,傳入一個組件,并返回一個組件。

(2)Render Props

先來看一段代碼:

// Render Props 的核心思想 // 1.通過一個函數,將class組件的state作為props,傳遞給純函數組件 class Factory extends React.Component {constructor() {tihs.state = {/* state 即多個組件的公共邏輯的數據 */}}/* 2.修改 state */render() {return <div>{this.props.render(this.state)}</div>} }const App = () => {// 3.在這里使用高階組件,同時將高階組件中的render屬性傳遞進來<Factory render={/* render 是一個函數組件 */(props) => <p>{props.a}{props.b}</p>} /> }export default App;

在上面的高階組件 HOC 中,最終返回的結果也是一個高階組件。但在 Render Props 中,我們把 Factory 包裹在定義的 App 組件中,最終再把 App 返回。

值得注意的是,在 Vue 中有類似于高階組件的用法,但沒有像 Render Props 類似的用法,這一點需要稍微留意一下。


下面來看一個例子,具體代碼如下:

import React from 'react' import PropTypes from 'prop-types'class Mouse extends React.Component {constructor(props) {super(props)this.state = { x: 0, y: 0 }}handleMouseMove = (event) => {this.setState({x: event.clientX,y: event.clientY})}render() {return (<div style={{ height: '500px' }} onMouseMove={this.handleMouseMove}>{/* 將當前 state 作為 props ,傳遞給 render (render 是一個函數組件) */}{this.props.render(this.state)}</div>)} } Mouse.propTypes = {render: PropTypes.func.isRequired // 必須接收一個 render 屬性,而且是函數 }const App = (props) => (<div style={{ height: '500px' }}><Mouse render={/* render 是一個函數組件 */({ x, y }) => <h1>The mouse position is ({x}, {y})</h1>}/></div> )/*** 即,定義了 Mouse 組件,只有獲取 x y 的能力。* 至于 Mouse 組件如何渲染,App 說了算,通過 render prop 的方式告訴 Mouse 。*/export default App

此時,瀏覽器的顯示效果如下:

在上面的代碼中,通過 this.props.render(this.state) 這種形式,將 Mouse 組件中的屬性傳遞給 App ,并讓 App 成功使用到 Mouse 的屬性值。

(3)HOC vs Render Props

現在,我們來梳理下 HOC 和 Render Props 的區別,具體如下:

  • HOC:模式簡單,但會增加組件層級
  • Render Props:代碼簡潔,學習成本較高
  • 各有各的優缺點,根據實際場景按需使用即可

📚三、Redux和React-router

1、Redux

(1)Redux概念簡述

對于 react 來說,它是一個非視圖層的輕量級框架,如果要用它來傳遞數據的話,則要先父傳子,然后再慢慢地一層一層往上傳遞。

但如果用 redux 的話,假設我們想要某個組件的數據,那這個組件的數據則會通過 redux 來存放到 store 中進行管理。之后呢,通過 store ,再來將數據一步步地往下面的組件進行傳遞。

值得注意的是,我們可以視 Redux 為 Reducer 和 Flux 的結合。

(2)Redux的工作流程

Redux ,實際上就是一個數據層的框架,它把所有的數據都放在了 store 之中。我們先來看一張圖:

大家可以看到中間的 store ,它里面就存放著所有的數據。繼續看 store 向下的箭頭,然后呢,每個組件都要向 store 里面去拿數據。

我們用一個例子來梳理整張圖,具體如下:

  • ①整張圖上有一個 store ,它存放著所有的數據,也就是存儲數據的公共區域
  • ②每個組件,都要從 store 里面拿數據;
  • ③假設現在有一個場景,模擬我們要在圖書館里面借書。那么我們可以把 react Component 理解為借書人,之后呢,借書人要去找圖書館管理員才能借到這本書。而借書這個過程中數據的傳遞,就可以把它視為是 Action Creators ,可以理解為 “你想要借什么書” 這句話。
  • ④ Action Creatures 去到 store 。這個時候我們把 store 當做是圖書館管理員,但是,圖書館管理員是沒有辦法記住所有圖書的數據情況的。一般來說,它都需要一個記錄本,你想要借什么樣的書,那么她就先查一下;又或者你想要還什么書,她也要查一下,需要放回什么位置上。
  • ⑤這個時候就需要跟 reducers 去通信,我們可以把 reducers 視為是一個記錄本,圖書館管理員用這個記錄本來記錄需要的數據。管理員 store 通過 reducer 知道了應該給借書人 Components 什么樣的數據。

(2)react-redux

React-redux 中要了解的幾個點是 Provider 、 Connect 、 mapStateToProps 和 mapDisptchToProps 。

來看以下代碼:

import React from 'react' import { Provider } from 'react-redux' import { createStore } from 'redux' import todoApp from './reducers' import App from './components/App'let store = createStore(todoApp)export default function() {return <Provider store={store}><App /></Provider> }

react-redux 提供了 Provider 的能力,大家可以看到最后部分的代碼, Provider 將 <App /> 包裹起來,其實也就是說為它包裹的所有組件提供 store 能力,這也是 Provider 發揮的作用。

再來看一段代碼:

import { connect } from 'react-redux' import { toggleTodo } from '../actions' import TodoList from '../components/TodoList'// 不同類型的 todo 列表 const getVisibleTodos = (todos, filter) => {switch (filter) {case 'SHOW_ALL':return todoscase 'SHOW_COMPLETED':return todos.filter(t => t.completed)case 'SHOW_ACTIVE':return todos.filter(t => !t.completed)} }const mapStateToProps = state => {// state 即 vuex 的總狀態,在 reducer/index.js 中定義return {// 根據完成狀態,篩選數據todos: getVisibleTodos(state.todos, state.visibilityFilter)} }const mapDispatchToProps = dispatch => {return {// 切換完成狀態onTodoClick: id => {dispatch(toggleTodo(id))}} }// connect 高階組件,將 state 和 dispatch 注入到組件 props 中 const VisibleTodoList = connect(mapStateToProps,mapDispatchToProps )(TodoList)export default VisibleTodoList

在上面的代碼中, connect 將 state 和 dispatch 給注入到組件的 props 中,將屬性傳遞給到 TodoList 組件。

(3)異步action

redux 中的同步 action 如下代碼所示:

// 同步 action export const addTodo = text => {// 返回 action 對象return {type: 'ADD_TODO',id: nextTodoId++,text} }

redux 中的異步 action 如下代碼所示:

// 異步 action export const addTodoAsync = text => {// 返回函數,其中有 dispatch 參數return (dispatch) => {// ajax 異步獲取數據fetch(url).thne(res => {// 執行異步 actiondispatch(addTodo(res.text))})} }

(4)Redux數據流圖

Redux 的單項數據流圖如下所示:

關于 Redux 更詳細內容,可查看這篇文章:Redux從入門到進階,看這一篇就夠了!

2、React-router

(1)路由模式

React-router 和 vue-router 一樣,都是兩種模式具體如下:

  • hash 模式(默認),如 http://abc.com/#/user/10
  • H5 history 模式,如 http://abc.com/user/20
  • 后者需要 server 端支持,因此無特殊需求可選擇前者

hash模式的路由配置如下代碼所示:

import React from 'react' import {HashRouter as Router,Switch,Route } from 'react-router-dom'function RouterComponent() {return(<Router><Switch><Route exact path="/"><Home /></Route><Route exact path="/project/:id"><Project /></Route><Route path="*"><NotFound /></Route></Switch></Router>) }

History模式的路由配置如下:

import React from 'react' import {BrowserRouter as Router,Switch,Route } from 'react-router-dom'function RouterComponent() {return(<Router><Switch><Route exact path="/"><Home /></Route><Route exact path="/project/:id"><Project /></Route><Route path="*"><NotFound /></Route></Switch></Router>) }

注意,hash 和 history 的區別在于 import 中的 HashRouter 和 BrowserRouter 。

關于 hash 和 history 相關的內容,進一步了解可查看這篇文章:淺談前端路由原理hash和history

(2)路由配置

Ⅰ. 動態路由

假設現在有父組件 RouterComponent ,具體代碼如下:

function RouterComponent() {return(<Router><Switch><Route exact path="/"><Home /></Route><Route exact path="/project/:id"><Project /></Route><Route path="*"><NotFound /></Route></Switch></Router>) }

其中,在這個組件中還有一個 Project 組件,需要進行動態傳參。


繼續,我們來看下子組件 Project 組件時如何進行動態傳參的。具體代碼如下:

import React from 'react' import { Link, useParams } from 'react-router-dom'function Project() {// 獲取 url 參數,如 '/project/100'const { id } = useParams()console.log('url param id', id)return (<div><Link to="/">首頁</Link></div>) }

大家可以看到,在 React 中,通過 const { id } = useParams() 這樣的形式,來進行動態傳參。


還有另外一種情況是跳轉路由請看以下代碼:

import React from 'react' import { useHistory } from 'react-router-dom'function Trash() {let history = useHistory()function handleClick() {history.push('/')}return (<div><Button type="primary" onClick={handleClick}>回到首頁</Button></div>) }

大家可以看到,通過使用 useHistory ,讓點擊事件跳轉到首頁中。

Ⅱ. 懶加載

import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import React, { Suspence, lazy } from 'react';const Home = lazy(() => import('./routes/Home')); const About lazy(() => import('./routes/About'));const App = () => {<Router><Suspense fallback={<div>Loading……</div>}><Switch><Route exact path="/" component={Home}/><Route path="/about" component={About}/></Switch></Suspense> </Router> }

在 React 中,我們可以直接用 lazy() 包裹,對頁面的內容進行懶加載。當然,還有另外一種情況是,加載類似于首頁初次加載頁面 Loading 的那種效果,在 react 中可以使用 <Suspense> 來解決。

🗞?四、結束語

在上面的文章中,我們講解了 react 的基本使用以及高級特性。同時,還講解了 react 的周邊插件, Redux 和 React-router 。

前端在做 react 的項目時,總是脫離不開以上文章所涉及到的知識點,唯一的區別在于基本使用的內容用的較多,而高級特性的使用場景相對會少一些。

希望通過上文的講解,小伙伴們有所收獲🥂

  • 關注公眾號 星期一研究室 ,第一時間關注學習干貨,更多 「offer來了」 面試專欄待你解鎖~
  • 如果這篇文章對你有用,記得留個腳印jio再走喲~
  • 我們下期見!🔑🔑🔑

總結

以上是生活随笔為你收集整理的探秘react,一文弄懂react的基本使用和高级特性的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

99精品视频免费在线观看 | av网站免费在线 | 黄色亚洲片 | 免费色婷婷 | 欧美精品九九99久久 | 精品国产乱码一区二 | 天堂在线视频免费观看 | 国产综合精品一区二区三区 | 欧美精品三级在线观看 | 97色狠狠 | 欧美亚洲xxx | 国产精品久久久久9999吃药 | 国产高清不卡在线 | 亚洲成年人免费网站 | 精品国产一二三四区 | 亚洲视频一 | 亚洲精品国产品国语在线 | 天天操夜夜爱 | 午夜丰满寂寞少妇精品 | 日韩三级精品 | 亚洲精品国产精品国自产观看浪潮 | 国产最新精品视频 | 激情综合五月网 | 国产视频黄 | 亚洲精品在线视频观看 | 成人蜜桃网 | 在线视频第一页 | 超碰在线日韩 | 中文字幕一区二区三区在线观看 | 亚洲人成人天堂h久久 | 亚洲精品国产精品久久99 | 日批视频在线观看免费 | 婷婷九月激情 | 天天爱天天色 | 成年人免费看av | av久久久久久 | 亚洲精品一区二区精华 | 久久艹艹 | 综合激情 | 狠狠干狠狠艹 | 久久久精品福利视频 | 国产伦理精品一区二区 | 69精品在线观看 | 亚洲一区欧美激情 | 黄色小视频在线观看免费 | 亚洲精品在线观看网站 | 欧美色久 | 国产精品久久久久影院 | 97在线免费观看视频 | 欧美大片www | 黄网站色 | 91麻豆操 | 欧美一级片播放 | 91最新中文字幕 | 日本黄色免费观看 | 91av视频导航 | 欧美夫妻生活视频 | 在线观看日韩 | 欧美一二三在线 | 中国黄色一级大片 | 中文字幕丰满人伦在线 | 91成人免费看片 | 99婷婷狠狠成为人免费视频 | 日韩电影在线观看一区 | 国产精品久久久久久一区二区 | 国内精品在线观看视频 | 国产一区二区网址 | 国产高清中文字幕 | 高清国产午夜精品久久久久久 | 午夜私人影院久久久久 | 日韩视频免费在线观看 | 精品一二三区视频 | 日韩中文字幕视频在线 | 久久爱综合| www亚洲精品 | 色综合久久久久综合 | 国产精品男女 | 国产网站在线免费观看 | 精品日本视频 | 91视频-88av | 国产特级毛片aaaaaa毛片 | 国产成人一区二区三区电影 | 人人爱人人舔 | 黄色不卡av | 欧美另类高清 | 国产视频欧美视频 | 久久免费视频6 | 丁香5月婷婷 | 国产一级免费视频 | 久久久国产一区二区三区四区小说 | 日韩久久精品一区二区 | 久草久草视频 | 国产探花视频在线播放 | 国产一区在线精品 | 成人久久久久久久久久 | 夜夜躁日日躁狠狠久久av | 国产一区在线精品 | 玖玖999| 亚洲高清久久久 | 成年人免费av网站 | 国产高清无线码2021 | 久久久国产精品一区二区三区 | 亚洲三级影院 | 国产在线欧美日韩 | 在线观看成人小视频 | 在线观看日韩免费视频 | 欧美日韩性视频在线 | 国产精品一区二区麻豆 | 日本在线观看视频一区 | 中文字幕资源站 | 日日夜夜婷婷 | 天天插狠狠插 | 超碰在线最新地址 | 五月婷婷丁香综合 | 亚洲欧美日本国产 | 欧美超碰在线 | 最近中文字幕在线播放 | 顶级bbw搡bbbb搡bbbb | 久久久久久网址 | 国产91精品一区二区 | 日韩国产欧美视频 | 91禁看片| 久久综合九色综合久久久精品综合 | 最近高清中文字幕在线国语5 | 91pony九色丨交换 | 夜夜躁日日躁狠狠久久88av | 黄色软件视频大全免费下载 | 午夜黄色 | 91免费看片黄 | 色网站黄 | 国内精品久久久久久久久 | 狠狠色丁香久久婷婷综合_中 | 久久中文精品视频 | 波多野结衣在线播放视频 | 91av原创| 激情av资源 | 在线亚洲天堂网 | 国际精品久久久 | 亚洲日本va中文字幕 | 夜夜躁日日躁 | 国产成人av在线 | 日本久久视频 | 久久精品看 | 国内精品视频久久 | 一级黄色片网站 | 日日噜噜噜噜夜夜爽亚洲精品 | 精品国产一二区 | 国产精品精品久久久久久 | 伊人干综合 | 日韩欧美一区二区在线播放 | 欧美日韩一区二区免费在线观看 | 国产69久久久 | 97碰在线| 国产视频久久久久 | 欧美一级电影免费观看 | 狠狠色综合网站久久久久久久 | 在线观看国产一区 | 日本不卡一区二区三区在线观看 | 日韩欧美久久 | 成人免费观看完整版电影 | 在线国产不卡 | 国产高清精| 欧美91精品国产自产 | 天天操比| 免费日韩 精品中文字幕视频在线 | 免费在线观看的av网站 | 天堂黄色片 | 久久精品成人 | 日日干天夜夜 | 亚洲第一av在线播放 | 999国产精品视频 | av成人在线电影 | 欧美日韩在线视频一区 | 一区 二区电影免费在线观看 | 天天人人| a在线一区| 免费亚洲成人 | 国产片免费在线观看视频 | 国内精品久久久久影院一蜜桃 | 日韩在线视频在线观看 | 中文字幕资源在线 | 日夜夜精品视频 | 久久久精品久久 | 91精品在线播放 | 在线观看久久久久久 | 色婷婷综合久色 | 91视频在线免费观看 | 精品国产乱码久久久久久三级人 | 国产经典 欧美精品 | 久久精品欧美一区二区三区麻豆 | 国产黄色片免费在线观看 | 午夜在线免费观看 | 97超碰国产精品 | 久久999精品| 欧美在线一二区 | 久99视频 | 精品主播网红福利资源观看 | www免费视频com━ | www.av在线播放 | 亚洲高清视频在线观看 | 久久综合九色综合久久久精品综合 | 色欧美日韩| 久久www免费人成看片高清 | 久久精品三 | 精品一区二区三区在线播放 | 在线精品在线 | 国产在线精品区 | 国产破处在线视频 | 欧美色插 | 日韩免费在线观看视频 | 一级片免费视频 | 国产视频一区二区在线观看 | 久久久五月婷婷 | 特黄特色特刺激视频免费播放 | 日日干精品 | 一级做a爱片性色毛片www | 玖玖视频 | 国产成人精品综合 | 在线视频欧美精品 | 国产综合激情 | 欧美日韩国产免费视频 | 天天干干 | 日韩在线视频不卡 | 不卡在线一区 | 国产一区麻豆 | 天天激情天天干 | 日韩av影视在线 | 夜夜操天天 | 懂色av一区二区三区蜜臀 | 欧美经典久久 | 亚洲日本精品视频 | 99国产免费网址 | 奇米影视777四色米奇影院 | 91免费在线视频 | 美女网站在线观看 | 国产欧美精品一区aⅴ影院 99视频国产精品免费观看 | 久久99精品久久久久蜜臀 | 国产精品com | 日韩69视频 | 午夜精品一区二区三区免费 | 久久亚洲私人国产精品 | 丰满少妇对白在线偷拍 | 西西大胆啪啪 | 欧美日韩在线视频免费 | 欧美另类69 | 97视频网址 | 免费网站黄 | 欧美 日韩 性 | 国产在线观看你懂得 | av电影av在线 | 婷香五月 | 娇妻呻吟一区二区三区 | 狠狠干狠狠艹 | 91视频传媒| 国产高清中文字幕 | 99国内精品| 日韩精品一区二区三区不卡 | 99精品久久久 | 国产精品一区二区三区电影 | 亚洲一级黄色片 | 国产福利一区二区三区在线观看 | 999成人免费视频 | 亚洲激情一区二区三区 | 99久久精品免费看国产四区 | 国产精品入口传媒 | 91免费视频国产 | 国产精品成人一区二区 | 日日干天天干 | 91免费在线视频 | 色综合久久综合中文综合网 | 久久a级片 | 久久人人97超碰精品888 | 91粉色视频| 麻豆一区二区三区视频 | 欧美男男tv网站 | 国内外成人免费在线视频 | 国产999视频 | 成人福利在线 | 午夜丁香视频在线观看 | 九九99靖品| 天天爽天天射 | 日韩簧片在线观看 | 天天操,夜夜操 | 免费在线观看国产精品 | 天天艹天天 | 中文字幕日韩av | 又长又大又黑又粗欧美 | 亚洲黄网址 | aa级黄色大片 | 久久精品美女视频 | 国产一区二区高清 | 91网站在线视频 | 国产精品麻豆一区二区三区 | 91久色蝌蚪| 欧美精品九九99久久 | 天天操天天操天天操天天 | www日韩在线观看 | 992tv人人草| 激情小说网站亚洲综合网 | 国产一区二区视频在线播放 | 日日射天天射 | 一区二区在线影院 | 日本中文字幕在线观看 | 超碰个人在线 | 日批视频在线播放 | 8x成人免费视频 | www.啪啪.com| 国产专区一 | 在线不卡中文字幕播放 | 国产一区免费观看 | 欧美一二在线 | 国产剧情在线一区 | .国产精品成人自产拍在线观看6 | 国产人成看黄久久久久久久久 | www.久久久com | 久久国产精品久久w女人spa | 97超碰人人模人人人爽人人爱 | 最近日本韩国中文字幕 | 青草视频在线 | 波多野结衣视频在线 | 午夜视频免费 | 亚洲成人中文在线 | 亚洲精品中文字幕在线 | 欧美日韩18 | 国产精品日韩久久久久 | 久久99这里只有精品 | 国产人免费人成免费视频 | 亚洲精品国偷拍自产在线观看蜜桃 | 中文字幕av全部资源www中文字幕在线观看 | 日韩精品一区二区三区高清免费 | 国产精品久久久久久久久久久免费 | 伊人看片 | 91精品在线免费观看 | 欧美综合色在线图区 | 日韩最新在线视频 | 久久久久久国产精品免费 | 成人免费视频在线观看 | 国内精品视频在线 | 一区二区三区四区精品 | 国产精品第二十页 | 免费在线观看黄网站 | 亚洲精品一区二区三区在线观看 | 免费视频在线观看网站 | 黄色网在线播放 | 超碰国产在线播放 | 干天天| 2024国产精品视频 | 激情综合色综合久久 | 在线观看日本高清mv视频 | 五月婷婷激情六月 | 成人免费视频网站在线观看 | 一区二区三区在线视频111 | 亚洲精品黄色在线观看 | 国产99亚洲 | 久久免费国产视频 | 久久成人人人人精品欧 | www.狠狠色| 日韩av成人 | 欧美日韩国产亚洲乱码字幕 | 91久久国产综合精品女同国语 | 久久成人精品电影 | 91av中文| 日韩中文字幕国产精品 | 欧美日本不卡 | 特级毛片网站 | 精品视频在线看 | 国产中文欧美日韩在线 | 91刺激视频 | 91女子私密保健养生少妇 | 亚洲精品自在在线观看 | 久久精品人人做人人综合老师 | 精品欧美乱码久久久久久 | 久久精品久久精品久久 | 处女av在线 | 日韩午夜一级片 | 中文在线免费视频 | 国产精品电影一区二区 | 色妞色视频一区二区三区四区 | 婷婷五天天在线视频 | 国产精品久久久久免费观看 | 日韩mv欧美mv国产精品 | 色网站免费在线看 | 久久国产系列 | 日韩亚洲在线视频 | 在线亚洲成人 | 最近更新中文字幕 | 国产精品原创在线 | 在线影视 一区 二区 三区 | 日日躁夜夜躁aaaaxxxx | 高清不卡毛片 | 天天操天天操天天爽 | 欧美二区三区91 | 中文字幕欧美日韩va免费视频 | 婷婷午夜激情 | 女人18片毛片90分钟 | 精品视频中文字幕 | 国模视频一区二区三区 | 成年人免费电影 | 深夜免费福利在线 | 久久国产热 | 99九九视频 | 免费观看av | 成人亚洲网 | 黄色av电影在线观看 | 色婷五月 | 国产色网站 | 国产高清av免费在线观看 | 亚洲免费成人 | 欧美特一级| 国产成人精品一二三区 | 国产精品成人免费精品自在线观看 | 午夜国产成人 | 日本精品视频在线 | 国产精品入口麻豆 | 国产91aaa| 一区在线播放 | 国内综合精品午夜久久资源 | 久久国产精品一区二区三区 | 欧美午夜精品久久久久久浪潮 | 久久五月婷婷丁香 | 色999在线 | 国产精品久久久久久久久费观看 | 午夜精品视频一区二区三区在线看 | 亚洲无毛专区 | 久久精品国亚洲 | 国产一区二区在线观看免费 | 色婷婷影视 | 久久人人爽人人爽 | 日p视频在线观看 | 午夜视频欧美 | 天天干天天拍天天操天天拍 | 黄色在线观看免费 | 激情视频一区 | 日韩理论视频 | 人交video另类hd | 香蕉91视频 | 又色又爽又黄 | 国产日韩精品一区二区三区在线 | 91网站在线视频 | 在线久久| 中国美女一级看片 | 欧美午夜a | 97在线视频观看 | 激情丁香综合五月 | 精品一二三四五区 | 成人av影视观看 | av天天澡天天爽天天av | 天天弄天天干 | 久草资源免费 | 婷婷视频导航 | 国产视频一区在线 | 国产成人精品一区二区三区福利 | 国产成人亚洲在线观看 | 99在线精品视频观看 | 日韩高清av| 99精品国产一区二区三区不卡 | 国模视频一区二区三区 | 国产精品毛片一区二区 | 日本女人b| 天天射天天操天天干 | 中文字幕观看在线 | 久草在线观看资源 | 白丝av免费观看 | 久久久久在线观看 | 午夜精品剧场 | 91精品国产91久久久久福利 | 久久成人在线视频 | 久久99精品久久久久久久久久久久 | 六月激情 | 又色又爽又黄 | 欧美另类交在线观看 | 国产视频精品视频 | 午夜免费福利视频 | 精品综合久久 | 国产高清专区 | 玖玖在线播放 | 久久久久国产成人免费精品免费 | 日本最大色倩网站www | 丁香在线 | 国产v亚洲v | 久热超碰 | 四虎永久国产精品 | 国产一级高清视频 | 日韩一二三 | 国产麻豆精品一区 | 欧美在线1区 | 欧美成人aa | 久久九九影视网 | 免费在线一区二区三区 | 国产成人在线观看 | 国产精品都在这里 | 日韩视频在线不卡 | 日韩久久久久久 | 91桃色免费视频 | av电影免费 | 欧美日韩视频网站 | av电影在线免费 | 中国成人一区 | 中日韩在线视频 | 91中文字幕在线播放 | 蜜臀av性久久久久蜜臀aⅴ四虎 | 免费观看v片在线观看 | 久久不卡国产精品一区二区 | 中文字幕在线观看视频网站 | 久久精品久久99 | 99高清视频有精品视频 | 99久久精品免费看国产四区 | 国产一区二区在线视频观看 | 人人草天天草 | 日韩网站视频 | 久久综合操 | 国产精品黄色影片导航在线观看 | 日本最大色倩网站www | 亚洲精品一区二区三区四区高清 | 久久久久国产精品www | 国产成人精品久久久久蜜臀 | 国产视频不卡 | 久久综合久久久 | 欧美性生活一级片 | 国产黄色片一级 | 97超碰免费在线观看 | 国产五码一区 | 欧美日韩视频网站 | 激情开心 | a天堂最新版中文在线地址 久久99久久精品国产 | 国产精品18久久久久久不卡孕妇 | 成人久久电影 | av成人免费在线看 | 亚洲 综合 精品 | 91精品黄色 | 亚洲综合精品视频 | 国产视频资源在线观看 | 二区三区毛片 | 操久久免费视频 | 国产一区二区影院 | 在线看av网址 | 狠狠色狠狠色终合网 | 久久久久五月 | 色五月成人| 97超碰免费| 在线影视 一区 二区 三区 | 亚洲国产成人在线观看 | 日韩综合在线观看 | 久久综合综合久久综合 | 久久字幕网| 中文字幕在线久一本久 | 在线电影av| 欧美a级成人淫片免费看 | 黄色av网站在线观看免费 | 亚洲精品99久久久久久 | 91色影院| 免费观看日韩av | 粉嫩av一区二区三区四区在线观看 | 999久久久久久久久6666 | 91丨九色丨国产在线 | 99热超碰| 一区二区欧美日韩 | 国产精久久久久久久 | 欧美国产在线看 | 91人人人 | 人人cao| 日本午夜在线亚洲.国产 | 国产精品色视频 | 久久精品婷婷 | 久久er99热精品一区二区 | 97成人在线观看视频 | 国内丰满少妇猛烈精品播放 | 国产亚洲免费的视频看 | 中文字幕丰满人伦在线 | 午夜精品福利一区二区 | 欧美精品二区 | 永久免费在线 | 欧美日韩中文在线 | 日韩电影中文字幕 | 日韩高清免费在线 | 国产精品乱码一区二三区 | 在线观看视频一区二区三区 | 五月天九九 | 三级a视频 | 91在线国产观看 | 9在线观看免费高清完整版在线观看明 | 国产成人综合在线观看 | 亚洲一区动漫 | 国产精品6999成人免费视频 | 日韩在线第一区 | 欧洲av在线 | 国产自偷自拍 | 国产成人精品一二三区 | 成人黄色大片在线免费观看 | 成人av网站在线播放 | 亚洲精品成人av在线 | 中文字幕在线日 | 日韩精品中文字幕在线播放 | 亚洲三级在线免费观看 | 久久综合毛片 | 久久免费视频网 | 国产精品中文字幕在线观看 | 亚洲国产无 | 日韩女同av| 日韩高清免费在线 | 在线a亚洲视频播放在线观看 | 网站免费黄色 | 99九九免费视频 | 九九免费在线观看视频 | 中文字幕高清免费日韩视频在线 | 亚洲精品国产日韩 | 久草在线精品观看 | 成人av资源在线 | 婷婷六月综合亚洲 | 91成人观看 | 久久av在线 | 92av视频| 国产精品高清一区二区三区 | 国产精品久久久久影院 | 国产日产欧美在线观看 | 亚洲成人动漫在线观看 | 日韩手机在线观看 | 人人草在线视频 | 久久综合九色欧美综合狠狠 | 日韩三级av | 四虎免费av| 久久99国产精品二区护士 | 久久久久久久久黄色 | 婷婷综合五月天 | 国产一级淫片在线观看 | 国产精品久99 | 午夜视频在线观看一区二区三区 | 亚洲黄色免费在线看 | 亚洲精品综合在线 | 国产一区二区高清不卡 | 国产又黄又猛又粗 | 91网免费观看 | 日韩色一区二区三区 | 婷婷激情小说网 | 超级碰视频 | 午夜久久精品 | 日韩在线视频网 | 久久国产电影 | 天天射天天操天天干 | 高清av影院 | 毛片网站免费 | 久久精品区 | 成人播放器 | 日韩在线一级 | 美女视频久久久 | 国产精品美女久久久久久免费 | 五月av在线| 黄色免费网站大全 | 国产精品高清在线观看 | 国产大陆亚洲精品国产 | 欧美激情精品久久久久 | 欧美色综合天天久久综合精品 | 亚洲精区二区三区四区麻豆 | 亚洲婷婷丁香 | 日日夜夜狠狠干 | 午夜视频在线观看一区二区三区 | 精品国产一区二区三区男人吃奶 | 97超碰在线久草超碰在线观看 | 99久久久国产精品免费观看 | 蜜臀久久99精品久久久久久网站 | 99久久999久久久精玫瑰 | 精品资源在线 | 亚洲精品456在线播放乱码 | 黄色毛片视频免费 | 99色| 96精品高清视频在线观看软件特色 | 国产a精品 | 久久精品成人欧美大片古装 | 欧美极品xxxxx | 亚洲经典在线 | 日本女人在线观看 | 亚洲丁香日韩 | av在线色 | 中文字幕在线观看不卡 | 依人成人综合网 | 久久视频这里只有精品 | 天天玩天天干 | 99福利片 | 欧美91精品 | 综合久久影院 | 97综合在线 | 99热99re6国产在线播放 | 国产在线日韩 | 亚洲最新视频在线 | www免费视频com| 午夜精品麻豆 | 嫩嫩影院理论片 | 国产一区在线视频 | 色就是色综合 | 91看片黄色 | 91片黄在线观看 | 在线视频 一区二区 | 成人精品视频久久久久 | 精品国产乱码一区二区三区在线 | 日韩欧美一二三 | 婷婷午夜天 | 久久精品伊人 | 成人午夜免费福利 | 欧美成人影音 | 亚洲国产资源 | 96久久欧美麻豆网站 | 欧美成年网站 | 天天射天天爱天天干 | 国产一级大片在线观看 | 国产免费久久精品 | 久久久一本精品99久久精品 | 欧美韩国日本在线 | 亚洲国内精品视频 | 一级免费看视频 | 91精品国产一区 | 97超碰成人在线 | 免费在线激情电影 | 337p日本欧洲亚洲大胆裸体艺术 | 欧美久久久久久久久久久久久 | 亚洲精品激情 | 午夜男人影院 | 国产精品观看 | 精品一区二区久久久久久久网站 | 制服丝袜在线 | 黄色a一级视频 | 一区二区网| 国产精品高清在线 | av在线在线 | www九九热 | 国产精品成人自拍 | 久久99久国产精品黄毛片入口 | 精品久久久久久国产 | 亚洲国产电影在线观看 | 免费网站色 | 欧美日本一二三 | 国产一区二区三区四区在线 | 四虎国产免费 | 1000部国产精品成人观看 | 久久国产精品免费 | www.狠狠操.com| 在线观看黄色 | 91视频久久| av片在线观看 | 欧美黄色免费 | 欧美另类美少妇69xxxx | 欧美专区亚洲专区 | 黄色小说18 | 深爱激情亚洲 | 四虎免费在线观看 | 一区二区久久久久 | 国产在线精品福利 | 综合网天天射 | 91亚洲精品视频 | 午夜久久| 2022国产精品视频 | 在线成人免费电影 | 高清av在线免费观看 | 丝袜美腿一区 | 免费在线一区二区三区 | www.久久久久 | 欧美一二区视频 | 精品久久一二三区 | 欧美日韩精品在线一区二区 | 性色视频在线 | 欧美另类调教 | 五月天中文在线 | 久久av在线播放 | 国产97色| 日日操日日操 | 久久99精品国产99久久6尤 | 亚洲黄色在线播放 | 日日操网 | 91看毛片| 亚洲视频第一页 | 日韩动漫免费观看高清完整版在线观看 | 日韩在线视频一区 | 97操操操| 久久久久亚洲精品男人的天堂 | 亚洲爱视频 | 久久免费视频在线 | 91精品国产综合久久福利不卡 | 成人免费视频视频在线观看 免费 | 啪啪免费试看 | 亚洲精品美女 | 日韩av伦理片 | 91色视频 | 91在线porny国产在线看 | 日韩在线视频免费看 | 色综合久久久久综合99 | 青青草国产在线 | 国产一区二区在线播放视频 | 日韩欧美综合视频 | 成人欧美在线 | 怡红院久久 | 欧美另类高潮 | 国产在线97| 黄色毛片网站在线观看 | 友田真希x88av | 国产 日韩 欧美 中文 在线播放 | 狠狠色丁香婷婷综合视频 | 激情 婷婷 | 丁香花在线观看免费完整版视频 | 在线视频麻豆 | 奇米影视8888 | 久久激五月天综合精品 | 91麻豆精品91久久久久同性 | 亚洲欧美综合精品久久成人 | 在线成人性视频 | 91精品视频免费在线观看 | 欧美性脚交 | 亚洲精品久久久久久久不卡四虎 | 亚洲 欧洲 国产 日本 综合 | 玖玖综合网 | 97看片网| 在线免费精品视频 | 在线精品视频在线观看高清 | 国产精品久久久久高潮 | 九九一级片| 国产一级特黄电影 | 久久99精品国产麻豆宅宅 | 亚洲五月婷 | 911av视频 | 99精品免费在线 | 国产高清视频 | 国产成人高清在线 | 91视频在线看 | 欧美一级日韩三级 | 精品国产一区二区三区在线观看 | 国产看片免费 | 亚洲视频在线播放 | 久草爱| 99精品热视频 | 精品主播网红福利资源观看 | 中文字幕免费 | 日韩偷拍精品 | 免费在线播放视频 | 在线观看aa | 国产美女主播精品一区二区三区 | 欧美日韩一区二区免费在线观看 | 亚洲欧美视频在线观看 | 国产一区二区三区免费视频 | 国产永久免费观看 | 欧美日本日韩aⅴ在线视频 插插插色综合 | 亚洲视频在线播放 | 久久无码av一区二区三区电影网 | 91中文字幕在线 | 久久伊人色综合 | 亚洲精品国产欧美在线观看 | 亚洲人久久| 一区二区欧美日韩 | 成人午夜久久 | 超碰人人超碰 | 国产电影一区二区三区四区 | 欧美片网站yy | 99r在线| 久久tv| 免费三级骚 | 亚洲全部视频 | 久久久久久久毛片 | 欧美国产日韩久久 | 日韩在线视频播放 | 国产精品美女在线观看 | 国产资源精品在线观看 | 97成人在线免费视频 | 成人av免费 | 久久婷婷网 | 96亚洲精品久久久蜜桃 | 久久久蜜桃| 婷婷性综合 | 国产精品一区二区久久精品 | 亚洲狠狠丁香婷婷综合久久久 | av在线免费观看网站 | 青青草国产精品 | 日韩欧美网站 | 人人澡人人爽欧一区 | 热久久免费视频精品 | 91自拍视频在线观看 | a在线免费观看视频 | 国产精品久久久久久吹潮天美传媒 | 中文字幕在线网址 | 欧美a级在线播放 | 国产视频综合在线 | 日韩精品免费在线观看视频 | 久久久久久久久久伊人 | 久久99婷婷| 人人狠狠| 欧美专区国产专区 | 欧美,日韩| 免费在线观看视频一区 | 日韩在线网址 | 国色天香第二季 | 一区二区三区在线免费播放 | 丁香六月婷婷开心婷婷网 | 国内精品久久久久久久影视简单 | 欧美a级片网站 | 午夜久久成人 | 美女视频黄网站 | 亚洲最新av网址 | 亚洲男男gaygay无套同网址 | 欧美性极品xxxx娇小 | 黄色av高清| 国产一区在线视频 | 日韩高清精品一区二区 | 天天激情天天干 | 深夜福利视频在线观看 | 成人精品99| 久久婷亚洲五月一区天天躁 | 超级碰碰免费视频 | 婷婷五天天在线视频 | 亚洲aⅴ一区二区三区 | 最近中文字幕完整视频高清1 | 国产欧美日韩视频 | 日韩无在线 | 国产精品v a免费视频 | 亚洲高清视频在线 | 久久婷婷国产 | 丁香六月天婷婷 | 亚洲人在线7777777精品 | 欧美一二三在线 | 国产日韩在线视频 | 欧洲色吧 | 美女久久久久久久久久 | 激情综合五月网 | 国产成人一区二区在线观看 | 日韩国产精品久久 | 99精品国产成人一区二区 | 69精品在线 | 在线观看91视频 | 久草免费在线视频 | 国产91学生粉嫩喷水 | 五月天中文在线 | 一区二区理论片 | 国产精品一区二区精品视频免费看 | 成人h电影| 在线国产片 | 一区二区三区三区在线 | 久久久久综合精品福利啪啪 | 69av久久| 一级黄视频 | 欧美日韩超碰 | 成人h电影| 久久免费视频7 | 成人久久| 综合色婷婷 | 黄色官网在线观看 | 国产精品video爽爽爽爽 | 国产视频一区二区在线播放 | 国产高清在线观看 | 黄色最新网址 | 天天干天天干天天操 | 国产视频在线播放 | 国产精品久久久久久久久久久久午 | 国产在线精品国自产拍影院 | 亚洲精品乱码久久久久久写真 | 黄色在线观看免费 | 国产精品久久久久久久久久久杏吧 | 婷婷丁香狠狠爱 | av综合 日韩 | 国产黄色高清 | 亚洲aⅴ一区二区三区 | 综合网五月天 | 国内精品久久天天躁人人爽 | 欧美日韩高清在线观看 | 97看片 | 国产精品精品国产色婷婷 | 欧美性春潮 | 国产福利在线 | 国产无套视频 | 免费在线观看av的网站 | 在线高清av | 日韩欧美高清视频在线观看 | 三级av在线免费观看 | 亚洲天天看 | 国产在线精品国自产拍影院 | 成人国产精品免费观看 | 久久综合久色欧美综合狠狠 | 狠狠黄 | av福利在线看 | 国产美女精品在线 | 人人干干人人 | 亚洲乱码中文字幕综合 | 91视频久久久 | 成人av网站在线 | 日本成人中文字幕在线观看 | 99热最新网址 | 日韩免费在线观看 | 久久99爱视频| 五月激情视频 | 激情在线网站 | av电影 一区二区 | 日韩精品欧美专区 | 97电影在线观看 | 欧美久久久一区二区三区 | 免费网站色 | 久久国产成人午夜av影院宅 | 久久国产香蕉视频 | 中文字幕专区高清在线观看 | 91手机电视 | 久久亚洲精品国产亚洲老地址 | 伊人婷婷 | 热久久这里只有精品 | 亚洲欧美日韩在线一区二区 | 亚洲三级av |