<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        30分鐘精通React今年最勁爆的新特性——React Hooks

        來源:懂視網 責編:小采 時間:2020-11-27 22:00:11
        文檔

        30分鐘精通React今年最勁爆的新特性——React Hooks

        30分鐘精通React今年最勁爆的新特性——React Hooks:你還在為該使用無狀態組件(Function)還是有狀態組件(Class)而煩惱嗎? ——擁有了hooks,你再也不需要寫Class了,你的所有組件都將是Function。 你還在為搞不清使用哪個生命周期鉤子函數而日夜難眠嗎? ——擁有了Hooks,生命周期鉤子函數可以先丟一邊
        推薦度:
        導讀30分鐘精通React今年最勁爆的新特性——React Hooks:你還在為該使用無狀態組件(Function)還是有狀態組件(Class)而煩惱嗎? ——擁有了hooks,你再也不需要寫Class了,你的所有組件都將是Function。 你還在為搞不清使用哪個生命周期鉤子函數而日夜難眠嗎? ——擁有了Hooks,生命周期鉤子函數可以先丟一邊

        你還在為該使用無狀態組件(Function)還是有狀態組件(Class)而煩惱嗎?
        ——擁有了hooks,你再也不需要寫Class了,你的所有組件都將是Function。

        你還在為搞不清使用哪個生命周期鉤子函數而日夜難眠嗎?
        ——擁有了Hooks,生命周期鉤子函數可以先丟一邊了。

        你在還在為組件中的this指向而暈頭轉向嗎?
        ——既然Class都丟掉了,哪里還有this?你的人生第一次不再需要面對this。

        這樣看來,說React Hooks是今年最勁爆的新特性真的毫不夸張。如果你也對react感興趣,或者正在使用react進行項目開發,答應我,請一定抽出至少30分鐘的時間來閱讀本文好嗎?所有你需要了解的React Hooks的知識點,本文都涉及到了,相信完整讀完后你一定會有所收獲。

        一個最簡單的Hooks

        首先讓我們看一下一個簡單的有狀態組件:

        class Example extends React.Component {
         constructor(props) {
         super(props);
         this.state = {
         count: 0
         };
         }
        
         render() {
         return (
         <div>
         <p>You clicked {this.state.count} times</p>
         <button onClick={() => this.setState({ count: this.state.count + 1 })}>
         Click me
         </button>
         </div>
         );
         }
        }

        我們再來看一下使用hooks后的版本:

        import { useState } from 'react';
        
        function Example() {
         const [count, setCount] = useState(0);
        
         return (
         <div>
         <p>You clicked {count} times</p>
         <button onClick={() => setCount(count + 1)}>
         Click me
         </button>
         </div>
         );
        }

        是不是簡單多了!可以看到,Example變成了一個函數,但這個函數卻有自己的狀態(count),同時它還可以更新自己的狀態(setCount)。這個函數之所以這么了不得,就是因為它注入了一個hook--useState,就是這個hook讓我們的函數變成了一個有狀態的函數。

        除了useState這個hook外,還有很多別的hook,比如useEffect提供了類似于componentDidMount等生命周期鉤子的功能,useContext提供了上下文(context)的功能等等。

        Hooks本質上就是一類特殊的函數,它們可以為你的函數型組件(function component)注入一些特殊的功能。咦?這聽起來有點像被詬病的Mixins啊?難道是Mixins要在react中死灰復燃了嗎?當然不會了,等會我們再來談兩者的區別。總而言之,這些hooks的目標就是讓你不再寫class,讓function一統江湖。

        React為什么要搞一個Hooks?

        想要復用一個有狀態的組件太麻煩了!

        我們都知道react都核心思想就是,將一個頁面拆成一堆獨立的,可復用的組件,并且用自上而下的單向數據流的形式將這些組件串聯起來。但假如你在大型的工作項目中用react,你會發現你的項目中實際上很多react組件冗長且難以復用。尤其是那些寫成class的組件,它們本身包含了狀態(state),所以復用這類組件就變得很麻煩。

        那之前,官方推薦怎么解決這個問題呢?答案是:渲染屬性(Render Props)和高階組件(Higher-Order Components)。我們可以稍微跑下題簡單看一下這兩種模式。

        渲染屬性指的是使用一個值為函數的prop來傳遞需要動態渲染的nodes或組件。如下面的代碼可以看到我們的DataProvider組件包含了所有跟狀態相關的代碼,而Cat組件則可以是一個單純的展示型組件,這樣一來DataProvider就可以單獨復用了。

        import Cat from 'components/cat'
        class DataProvider extends React.Component {
         constructor(props) {
         super(props);
         this.state = { target: 'Zac' };
         }
        
         render() {
         return (
         <div>
         {this.props.render(this.state)}
         </div>
         )
         }
        }
        
        <DataProvider render={data => (
         <Cat target={data.target} />
        )}/>

        雖然這個模式叫Render Props,但不是說非用一個叫render的props不可,習慣上大家更常寫成下面這種:

        ...
        <DataProvider>
         {data => (
         <Cat target={data.target} />
         )}
        </DataProvider>

        高階組件這個概念就更好理解了,說白了就是一個函數接受一個組件作為參數,經過一系列加工后,最后返回一個新的組件。看下面的代碼示例,withUser函數就是一個高階組件,它返回了一個新的組件,這個組件具有了它提供的獲取用戶信息的功能。

        const withUser = WrappedComponent => {
         const user = sessionStorage.getItem("user");
         return props => <WrappedComponent user={user} {...props} />;
        };
        
        const UserPage = props => (
         <div class="user-container">
         <p>My name is {props.user}!</p>
         </div>
        );
        
        export default withUser(UserPage);

        以上這兩種模式看上去都挺不錯的,很多庫也運用了這種模式,比如我們常用的React Router。但我們仔細看這兩種模式,會發現它們會增加我們代碼的層級關系。最直觀的體現,打開devtool看看你的組件層級嵌套是不是很夸張吧。這時候再回過頭看我們上一節給出的hooks例子,是不是簡潔多了,沒有多余的層級嵌套。把各種想要的功能寫成一個一個可復用的自定義hook,當你的組件想用什么功能時,直接在組件里調用這個hook即可。

        生命周期鉤子函數里的邏輯太亂了吧!

        我們通常希望一個函數只做一件事情,但我們的生命周期鉤子函數里通常同時做了很多事情。比如我們需要在componentDidMount中發起ajax請求獲取數據,綁定一些事件監聽等等。同時,有時候我們還需要在componentDidUpdate做一遍同樣的事情。當項目變復雜后,這一塊的代碼也變得不那么直觀。

        classes真的太讓人困惑了!

        我們用class來創建react組件時,還有一件很麻煩的事情,就是this的指向問題。為了保證this的指向正確,我們要經常寫這樣的代碼:this.handleClick = this.handleClick.bind(this),或者是這樣的代碼:<button onClick={() => this.handleClick(e)}>。一旦我們不小心忘了綁定this,各種bug就隨之而來,很麻煩。

        還有一件讓我很苦惱的事情。我在之前的react系列文章當中曾經說過,盡可能把你的組件寫成無狀態組件的形式,因為它們更方便復用,可獨立測試。然而很多時候,我們用function寫了一個簡潔完美的無狀態組件,后來因為需求變動這個組件必須得有自己的state,我們又得很麻煩的把function改成class。

        在這樣的背景下,Hooks便橫空出世了!

        什么是State Hooks?

        回到一開始我們用的例子,我們分解來看到底state hooks做了什么:

        import { useState } from 'react';
        
        function Example() {
         const [count, setCount] = useState(0);
        
         return (
         <div>
         <p>You clicked {count} times</p>
         <button onClick={() => setCount(count + 1)}>
         Click me
         </button>
         </div>
         );
        }

        聲明一個狀態變量

        import { useState } from 'react';
        
        function Example() {
         const [count, setCount] = useState(0);

        useState是react自帶的一個hook函數,它的作用就是用來聲明狀態變量。useState這個函數接收的參數是我們的狀態初始值(initial state),它返回了一個數組,這個數組的第[0]項是當前當前的狀態值,第[1]項是可以改變狀態值的方法函數。

        所以我們做的事情其實就是,聲明了一個狀態變量count,把它的初始值設為0,同時提供了一個可以更改count的函數setCount。

        上面這種表達形式,是借用了es6的數組解構(array destructuring),它可以讓我們的代碼看起來更簡潔。不清楚這種用法的可以先去看下我的這篇文章30分鐘掌握ES6/ES2015核心內容(上)。

        如果不用數組解構的話,可以寫成下面這樣。實際上數組解構是一件開銷很大的事情,用下面這種寫法,或者改用對象解構,性能會有很大的提升。具體可以去這篇文章的分析Array destructuring for multi-value returns (in light of React hooks),這里不詳細展開,我們就按照官方推薦使用數組解構就好。

        let _useState = useState(0);
        let count = _useState[0];
        let setCount = _useState[1];

        讀取狀態值

        <p>You clicked {count} times</p>

        是不是超簡單?因為我們的狀態count就是一個單純的變量而已,我們再也不需要寫成{this.state.count}這樣了。

        更新狀態

         <button onClick={() => setCount(count + 1)}>
         Click me
         </button>

        當用戶點擊按鈕時,我們調用setCount函數,這個函數接收的參數是修改過的新狀態值。接下來的事情就交給react了,react將會重新渲染我們的Example組件,并且使用的是更新后的新的狀態,即count=1。這里我們要停下來思考一下,Example本質上也是一個普通的函數,為什么它可以記住之前的狀態?

        一個至關重要的問題

        這里我們就發現了問題,通常來說我們在一個函數中聲明的變量,當函數運行完成后,這個變量也就銷毀了(這里我們先不考慮閉包等情況),比如考慮下面的例子:

        function add(n) {
         const result = 0;
         return result + 1;
        }
        
        add(1); //1
        add(1); //1

        不管我們反復調用add函數多少次,結果都是1。因為每一次我們調用add時,result變量都是從初始值0開始的。那為什么上面的Example函數每次執行的時候,都是拿的上一次執行完的狀態值作為初始值?答案是:是react幫我們記住的。至于react是用什么機制記住的,我們可以再思考一下。

        假如一個組件有多個狀態值怎么辦?

        首先,useState是可以多次調用的,所以我們完全可以這樣寫:

        function ExampleWithManyStates() {
         const [age, setAge] = useState(42);
         const [fruit, setFruit] = useState('banana');
         const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

        其次,useState接收的初始值沒有規定一定要是string/number/boolean這種簡單數據類型,它完全可以接收對象或者數組作為參數。唯一需要注意的點是,之前我們的this.setState做的是合并狀態后返回一個新狀態,而useState是直接替換老狀態后返回新狀態。最后,react也給我們提供了一個useReducer的hook,如果你更喜歡redux式的狀態管理方案的話。

        從ExampleWithManyStates函數我們可以看到,useState無論調用多少次,相互之間是獨立的。這一點至關重要。為什么這么說呢?

        其實我們看hook的“形態”,有點類似之前被官方否定掉的Mixins這種方案,都是提供一種“插拔式的功能注入”的能力。而mixins之所以被否定,是因為Mixins機制是讓多個Mixins共享一個對象的數據空間,這樣就很難確保不同Mixins依賴的狀態不發生沖突。

        而現在我們的hook,一方面它是直接用在function當中,而不是class;另一方面每一個hook都是相互獨立的,不同組件調用同一個hook也能保證各自狀態的獨立性。這就是兩者的本質區別了。

        react是怎么保證多個useState的相互獨立的?

        還是看上面給出的ExampleWithManyStates例子,我們調用了三次useState,每次我們傳的參數只是一個值(如42,‘banana'),我們根本沒有告訴react這些值對應的key是哪個,那react是怎么保證這三個useState找到它對應的state呢?

        答案是,react是根據useState出現的順序來定的。我們具體來看一下:

         //第一次渲染
         useState(42); //將age初始化為42
         useState('banana'); //將fruit初始化為banana
         useState([{ text: 'Learn Hooks' }]); //...
        
         //第二次渲染
         useState(42); //讀取狀態變量age的值(這時候傳的參數42直接被忽略)
         useState('banana'); //讀取狀態變量fruit的值(這時候傳的參數banana直接被忽略)
         useState([{ text: 'Learn Hooks' }]); //...

        假如我們改一下代碼:

        let showFruit = true;
        function ExampleWithManyStates() {
         const [age, setAge] = useState(42);
         
         if(showFruit) {
         const [fruit, setFruit] = useState('banana');
         showFruit = false;
         }
         
         const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

        這樣一來,

         //第一次渲染
         useState(42); //將age初始化為42
         useState('banana'); //將fruit初始化為banana
         useState([{ text: 'Learn Hooks' }]); //...
        
         //第二次渲染
         useState(42); //讀取狀態變量age的值(這時候傳的參數42直接被忽略)
         // useState('banana'); 
         useState([{ text: 'Learn Hooks' }]); //讀取到的卻是狀態變量fruit的值,導致報錯

        鑒于此,react規定我們必須把hooks寫在函數的最外層,不能寫在ifelse等條件語句當中,來確保hooks的執行順序一致。

        什么是Effect Hooks?

        我們在上一節的例子中增加一個新功能:

        import { useState, useEffect } from 'react';
        
        function Example() {
         const [count, setCount] = useState(0);
        
         // 類似于componentDidMount 和 componentDidUpdate:
         useEffect(() => {
         // 更新文檔的標題
         document.title = `You clicked ${count} times`;
         });
        
         return (
         <div>
         <p>You clicked {count} times</p>
         <button onClick={() => setCount(count + 1)}>
         Click me
         </button>
         </div>
         );
        }

        我們對比著看一下,如果沒有hooks,我們會怎么寫?

        class Example extends React.Component {
         constructor(props) {
         super(props);
         this.state = {
         count: 0
         };
         }
        
         componentDidMount() {
         document.title = `You clicked ${this.state.count} times`;
         }
        
         componentDidUpdate() {
         document.title = `You clicked ${this.state.count} times`;
         }
        
         render() {
         return (
         <div>
         <p>You clicked {this.state.count} times</p>
         <button onClick={() => this.setState({ count: this.state.count + 1 })}>
         Click me
         </button>
         </div>
         );
         }
        }

        我們寫的有狀態組件,通常會產生很多的副作用(side effect),比如發起ajax請求獲取數據,添加一些監聽的注冊和取消注冊,手動修改dom等等。我們之前都把這些副作用的函數寫在生命周期函數鉤子里,比如componentDidMount,componentDidUpdate和componentWillUnmount。而現在的useEffect就相當與這些聲明周期函數鉤子的集合體。它以一抵三。

        同時,由于前文所說hooks可以反復多次使用,相互獨立。所以我們合理的做法是,給每一個副作用一個單獨的useEffect鉤子。這樣一來,這些副作用不再一股腦堆在生命周期鉤子里,代碼變得更加清晰。

        useEffect做了什么?

        我們再梳理一遍下面代碼的邏輯:

        function Example() {
         const [count, setCount] = useState(0);
        
         useEffect(() => {
         document.title = `You clicked ${count} times`;
         });

        首先,我們聲明了一個狀態變量count,將它的初始值設為0。然后我們告訴react,我們的這個組件有一個副作用。我們給useEffecthook傳了一個匿名函數,這個匿名函數就是我們的副作用。在這個例子里,我們的副作用是調用browser API來修改文檔標題。當react要渲染我們的組件時,它會先記住我們用到的副作用。等react更新了DOM之后,它再依次執行我們定義的副作用函數。

        這里要注意幾點:

        第一,react首次渲染和之后的每次渲染都會調用一遍傳給useEffect的函數。而之前我們要用兩個聲明周期函數來分別表示首次渲染(componentDidMount),和之后的更新導致的重新渲染(componentDidUpdate)。

        第二,useEffect中定義的副作用函數的執行不會阻礙瀏覽器更新視圖,也就是說這些函數是異步執行的,而之前的componentDidMount或componentDidUpdate中的代碼則是同步執行的。這種安排對大多數副作用說都是合理的,但有的情況除外,比如我們有時候需要先根據DOM計算出某個元素的尺寸再重新渲染,這時候我們希望這次重新渲染是同步發生的,也就是說它會在瀏覽器真的去繪制這個頁面前發生。

        useEffect怎么解綁一些副作用

        這種場景很常見,當我們在componentDidMount里添加了一個注冊,我們得馬上在componentWillUnmount中,也就是組件被注銷之前清除掉我們添加的注冊,否則內存泄漏的問題就出現了。

        怎么清除呢?讓我們傳給useEffect的副作用函數返回一個新的函數即可。這個新的函數將會在組件下一次重新渲染之后執行。這種模式在一些pubsub模式的實現中很常見。看下面的例子:

        import { useState, useEffect } from 'react';
        
        function FriendStatus(props) {
         const [isOnline, setIsOnline] = useState(null);
        
         function handleStatusChange(status) {
         setIsOnline(status.isOnline);
         }
        
         useEffect(() => {
         ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
         // 一定注意下這個順序:告訴react在下次重新渲染組件之后,同時是下次調用ChatAPI.subscribeToFriendStatus之前執行cleanup
         return function cleanup() {
         ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
         };
         });
        
         if (isOnline === null) {
         return 'Loading...';
         }
         return isOnline ? 'Online' : 'Offline';
        }

        這里有一個點需要重視!這種解綁的模式跟componentWillUnmount不一樣。componentWillUnmount只會在組件被銷毀前執行一次而已,而useEffect里的函數,每次組件渲染后都會執行一遍,包括副作用函數返回的這個清理函數也會重新執行一遍。所以我們一起來看一下下面這個問題。

        為什么要讓副作用函數每次組件更新都執行一遍?

        我們先看以前的模式:

         componentDidMount() {
         ChatAPI.subscribeToFriendStatus(
         this.props.friend.id,
         this.handleStatusChange
         );
         }
        
         componentWillUnmount() {
         ChatAPI.unsubscribeFromFriendStatus(
         this.props.friend.id,
         this.handleStatusChange
         );
         }

        很清除,我們在componentDidMount注冊,再在componentWillUnmount清除注冊。但假如這時候props.friend.id變了怎么辦?我們不得不再添加一個componentDidUpdate來處理這種情況:

        ...
         componentDidUpdate(prevProps) {
         // 先把上一個friend.id解綁
         ChatAPI.unsubscribeFromFriendStatus(
         prevProps.friend.id,
         this.handleStatusChange
         );
         // 再重新注冊新但friend.id
         ChatAPI.subscribeToFriendStatus(
         this.props.friend.id,
         this.handleStatusChange
         );
         }
        ...

        看到了嗎?很繁瑣,而我們但useEffect則沒這個問題,因為它在每次組件更新后都會重新執行一遍。所以代碼的執行順序是這樣的:

        1.頁面首次渲染
        2.替friend.id=1的朋友注冊
        3.突然friend.id變成了2
        4.頁面重新渲染
        5.清除friend.id=1的綁定
        6.替friend.id=2的朋友注冊
        ...

        怎么跳過一些不必要的副作用函數

        按照上一節的思路,每次重新渲染都要執行一遍這些副作用函數,顯然是不經濟的。怎么跳過一些不必要的計算呢?我們只需要給useEffect傳第二個參數即可。用第二個參數來告訴react只有當這個參數的值發生改變時,才執行我們傳的副作用函數(第一個參數)。

        useEffect(() => {
         document.title = `You clicked ${count} times`;
        }, [count]); // 只有當count的值發生變化時,才會重新執行`document.title`這一句

        當我們第二個參數傳一個空數組[]時,其實就相當于只在首次渲染的時候執行。也就是componentDidMount加componentWillUnmount的模式。不過這種用法可能帶來bug,少用。

        還有哪些自帶的Effect Hooks?

        除了上文重點介紹的useState和useEffect,react還給我們提供來很多有用的hooks:

      1. useContext
      2. useReducer
      3. useCallback
      4. useMemo
      5. useRef
      6. useImperativeMethods
      7. useMutationEffect
      8. useLayoutEffect
      9. 我不再一一介紹,大家自行去查閱官方文檔。

        怎么寫自定義的Effect Hooks?

        為什么要自己去寫一個Effect Hooks? 這樣我們才能把可以復用的邏輯抽離出來,變成一個個可以隨意插拔的“插銷”,哪個組件要用來,我就插進哪個組件里,so easy!看一個完整的例子,你就明白了。

        比如我們可以把上面寫的FriendStatus組件中判斷朋友是否在線的功能抽出來,新建一個useFriendStatus的hook專門用來判斷某個id是否在線。

        import { useState, useEffect } from 'react';
        
        function useFriendStatus(friendID) {
         const [isOnline, setIsOnline] = useState(null);
        
         function handleStatusChange(status) {
         setIsOnline(status.isOnline);
         }
        
         useEffect(() => {
         ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
         return () => {
         ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
         };
         });
        
         return isOnline;
        }

        這時候FriendStatus組件就可以簡寫為:

        function FriendStatus(props) {
         const isOnline = useFriendStatus(props.friend.id);
        
         if (isOnline === null) {
         return 'Loading...';
         }
         return isOnline ? 'Online' : 'Offline';
        }

        簡直Perfect!假如這個時候我們又有一個朋友列表也需要顯示是否在線的信息:

        function FriendListItem(props) {
         const isOnline = useFriendStatus(props.friend.id);
        
         return (
         <li style={{ color: isOnline ? 'green' : 'black' }}>
         {props.friend.name}
         </li>
         );
        }

        簡直Fabulous!

        結尾

        不知道你閱讀完整篇文章的感受如何,或者對hooks有任何角度的看法和思考都歡迎在評論區一起討論。另外如果你有換工作的打算,我們部門真的很缺人,歡迎私信勾搭~

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        30分鐘精通React今年最勁爆的新特性——React Hooks

        30分鐘精通React今年最勁爆的新特性——React Hooks:你還在為該使用無狀態組件(Function)還是有狀態組件(Class)而煩惱嗎? ——擁有了hooks,你再也不需要寫Class了,你的所有組件都將是Function。 你還在為搞不清使用哪個生命周期鉤子函數而日夜難眠嗎? ——擁有了Hooks,生命周期鉤子函數可以先丟一邊
        推薦度:
        標簽: 30分鐘 React hooks
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 3344永久在线观看视频免费首页| 色老板亚洲视频免在线观| 美女免费视频一区二区| 大学生一级特黄的免费大片视频| 亚洲人成电影网站| 性生交片免费无码看人| 在线观看日本亚洲一区| 成人免费视频国产| 免费看黄福利app导航看一下黄色录像| 日韩精品视频免费网址| 男人和女人高潮免费网站| 亚洲精品97久久中文字幕无码| 黄色毛片免费在线观看| 亚洲色欲久久久久综合网| 国产久爱免费精品视频| 亚洲成色WWW久久网站| 98精品全国免费观看视频| 亚洲日韩乱码中文无码蜜桃| 一个人免费观看www视频在线| 中文字幕乱码亚洲无线三区| 国产精品深夜福利免费观看| 日韩精品无码永久免费网站| 国产亚洲真人做受在线观看| 99精品视频在线免费观看| 激情综合亚洲色婷婷五月| 国产中文字幕免费观看| 久青草视频97国内免费影视| 久久夜色精品国产噜噜亚洲AV| 精品国产无限资源免费观看| 最新亚洲人成无码网www电影| 亚洲午夜久久久久久久久久| 8090在线观看免费观看| 日韩色日韩视频亚洲网站| 久久精品国产亚洲Aⅴ香蕉| 无码A级毛片免费视频内谢| 亚洲va精品中文字幕| 亚洲精品综合久久| 99视频有精品视频免费观看| 精品在线观看免费| 亚洲自偷自拍另类图片二区| 国产精品免费_区二区三区观看|