<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          React Hooks 使用誤區(qū),駁官方文檔

          共 10178字,需瀏覽 21分鐘

           ·

          2021-12-28 14:21

          大綱

          • 1. 不是所有的依賴(lài)都必須放到依賴(lài)數(shù)組中

          • 2. deps 參數(shù)不能緩解閉包問(wèn)題

            • 2.1 正常情況下是不會(huì)有閉包問(wèn)題的

            • 2.2 延遲調(diào)用會(huì)存在閉包問(wèn)題

          • 3. 盡量不要用 useCallback

            • 3.1 useCallback 大部分場(chǎng)景沒(méi)有提升性能

            • 3.2 useCallback 讓代碼可讀性變差

          • 4. useMemo 建議適當(dāng)使用

          • 5. useState 的正確使用姿勢(shì)

            • 5.1 能用其他狀態(tài)計(jì)算出來(lái)就不用單獨(dú)聲明狀態(tài)

            • 5.2 保證數(shù)據(jù)源唯一

            • 5.3 useState 適當(dāng)合并

          • 6、總結(jié)

          正文

          作為 React Hooks 庫(kù) ahooks[1] 的作者,我應(yīng)該算一個(gè)非常非常資深的 React Hooks 用戶(hù)。在兩年多的 React Hooks 使用過(guò)程中,我越來(lái)越發(fā)現(xiàn)大家(包括我自己)對(duì) React Hooks 的使用姿勢(shì)存在很大誤區(qū),歸根到底是官方文檔的教程很不嚴(yán)謹(jǐn),存在錯(cuò)誤的指引。

          1. 不是所有的依賴(lài)都必須放到依賴(lài)數(shù)組中

          對(duì)于所有的 React Hooks 用戶(hù),都有一個(gè)共識(shí):“useEffect 中使用到外部變量,都應(yīng)該放到第二個(gè)數(shù)組參數(shù)中”,同時(shí)我們會(huì)安裝 eslint-plugin-react-hooks[2] 插件,來(lái)提醒自己是不是忘了某些變量。

          以上共識(shí)來(lái)自官方文檔:

          我愿稱(chēng)該條規(guī)則為萬(wàn)惡之源,這條規(guī)則以高亮展示,所有的新人都很重視,包括我自己。然而在實(shí)際的開(kāi)發(fā)中,發(fā)現(xiàn)事情并不是這樣的。

          下面舉一個(gè)比較簡(jiǎn)單的例子,要求如下:當(dāng) props.countcount 變化時(shí),上報(bào)當(dāng)前所有數(shù)據(jù)。

          這個(gè)例子比較簡(jiǎn)單,先貼下源碼:

          function?Demo(props)?{
          ??const?[count,?setCount]?=?useState(0);
          ??const?[text,?setText]?=?useState('');
          ??const?[a,?setA]?=?useState('');

          ??useEffect(()?=>?{
          ????monitor(props.count,?count,?text,?a);
          ??},?[props.count,?count]);

          ??return?(
          ????<div>
          ??????<button
          ????????onClick={()?=>
          ?setCount(c?=>?c?+?1)}
          ??????>
          ????????click
          ??????button>

          ??????<input?value={text}?onChange={e?=>?setText(e.target.value)}?/>
          ??????<input?value={a}?onChange={e?=>?setA(e.target.value)}?/>
          ????div>
          ??)
          }

          我們能看到示例代碼中,useEffect 是不符合 React 官方建議的,texta 變量沒(méi)有放到依賴(lài)數(shù)組中,ESLint 警告如下:

          img

          那如果按照規(guī)范,我們把依賴(lài)項(xiàng)都放到第二個(gè)數(shù)組參數(shù)中,會(huì)怎樣呢?

          ??useEffect(()?=>?{
          ????monitor(props.count,?count,?text,?a);
          ??},?[props.count,?count,?text,?a]);

          如上的代碼雖然符合了 React 官方的規(guī)范,但不滿(mǎn)足我們的業(yè)務(wù)需求了,當(dāng) texta 變化時(shí),也觸發(fā)了函數(shù)執(zhí)行。

          此時(shí)陷入了困境,當(dāng)滿(mǎn)足 useEffect 使用規(guī)范時(shí),業(yè)務(wù)需求就不能滿(mǎn)足了。當(dāng)滿(mǎn)足業(yè)務(wù)需求時(shí),useEffect 就不規(guī)范了。

          我的建議為:

          1. 不要使用 eslint-plugin-react-hooks 插件,或者可以選擇性忽略該插件的警告。
          2. 只有一種情況,需要把變量放到 deps 數(shù)組中,那就是當(dāng)該變量變化時(shí),需要觸發(fā) useEffect 函數(shù)執(zhí)行。而不是因?yàn)?useEffect 中用到了這個(gè)變量!

          2. deps 參數(shù)不能緩解閉包問(wèn)題

          假如完全按第二個(gè)建議來(lái)寫(xiě)代碼,很多人又擔(dān)心,會(huì)不會(huì)造成一些不必要的閉包問(wèn)題?我的結(jié)論是:閉包問(wèn)題和 useEffect 的 deps 參數(shù)沒(méi)有太大關(guān)系。

          比如我有一個(gè)這樣的需求:當(dāng)進(jìn)入頁(yè)面 3s 后,輸出當(dāng)前最新的 count。代碼如下:

          function?Demo()?{
          ??const?[count,?setCount]?=?useState(0);

          ??useEffect(()?=>?{
          ????const?timer?=?setTimeout(()?=>?{
          ??????console.log(count)
          ????},?3000);
          ????return?()?=>?{
          ??????clearTimeout(timer);
          ????}
          ??},?[])

          ??return?(
          ????<button
          ??????onClick={()?=>
          ?setCount(c?=>?c?+?1)}
          ????>
          ??????click
          ????button>

          ??)
          }

          以上代碼,實(shí)現(xiàn)了初始化 3s 后,輸出 count。但很遺憾,這里肯定會(huì)出閉包問(wèn)題,哪怕進(jìn)來(lái)之后我們多次點(diǎn)擊了 button,輸出的 count 仍然為 0。

          那假如我們把 count 放到 deps 中,是不是就好了?

          ??useEffect(()?=>?{
          ????const?timer?=?setTimeout(()?=>?{
          ??????console.log(count)
          ????},?3000);
          ????return?()?=>?{
          ??????clearTimeout(timer);
          ????}
          ??},?[count])

          如上代碼,此時(shí)確實(shí)沒(méi)有閉包問(wèn)題了,但在每次 count 變化時(shí),定時(shí)器卸載并重新開(kāi)始計(jì)時(shí)了,不滿(mǎn)足我們的最初需求了。

          要解決的唯一辦法為:

          const?[count,?setCount]?=?useState(0);

          //?通過(guò)?ref?來(lái)記憶最新的?count
          const?countRef?=?useRef(count);
          countRef.current?=?count;

          useEffect(()?=>?{
          ??const?timer?=?setTimeout(()?=>?{
          ????console.log(countRef.current)
          ??},?3000);
          ??return?()?=>?{
          ????clearTimeout(timer);
          ??}
          },?[])

          雖然上面的代碼,很繞,但確實(shí),只有這個(gè)解決方案。請(qǐng)記住這段代碼,功能真的很強(qiáng)大。

          const?countRef?=?useRef(count);
          countRef.current?=?count;

          上面的例子,可以發(fā)現(xiàn),閉包問(wèn)題是不能僅僅通過(guò)遵守 React 規(guī)則來(lái)避免的。我們必須清晰的知道,在什么場(chǎng)景下會(huì)出現(xiàn)閉包問(wèn)題。

          2.1 正常情況下是不會(huì)有閉包問(wèn)題的

          const?[a,?setA]?=?useState(0);
          const?[b,?setB]?=?useState(0);

          const?c?=?a?+?b;

          useEffect(()=>{
          ?console.log(a,?b,?c)
          },?[a]);

          useEffect(()=>{
          ?console.log(a,?b,?c)
          },?[b]);

          useEffect(()=>{
          ?console.log(a,?b,?c)
          },?[c]);

          在一般的使用過(guò)程中,是不會(huì)有閉包問(wèn)題的,如上代碼中,完全不會(huì)有閉包問(wèn)題,和 deps 怎么寫(xiě)沒(méi)有任何關(guān)系。

          2.2 延遲調(diào)用會(huì)存在閉包問(wèn)題

          在延遲調(diào)用的場(chǎng)景下,一定會(huì)存在閉包問(wèn)題。 什么是延遲調(diào)用?

          1. 使用 setTimeout、setInterval、Promise.then 等
          2. useEffect 的卸載函數(shù)
          const?getUsername?=?()?=>?{
          ??return?new?Promise((resolve,?reject)?=>?{
          ????setTimeout(()?=>?{
          ??????resolve('John');
          ????},?3000);
          ??})
          }

          function?Demo()?{
          ??const?[count,?setCount]?=?useState(0);

          ??//?setTimeout?會(huì)造成閉包問(wèn)題
          ??useEffect(()?=>?{
          ????const?timer?=?setTimeout(()?=>?{
          ??????console.log(count);
          ????},?3000);
          ????return?()?=>?{
          ??????clearTimeout(timer);
          ????}
          ??},?[])

          ??//?setInterval?會(huì)造成閉包問(wèn)題
          ??useEffect(()?=>?{
          ????const?timer?=?setInterval(()?=>?{
          ??????console.log(count);
          ????},?3000);
          ????return?()?=>?{
          ??????clearInterval(timer);
          ????}
          ??},?[])

          ??//?Promise.then?會(huì)造成閉包問(wèn)題
          ??useEffect(()?=>?{
          ????getUsername().then(()?=>?{
          ??????console.log(count);
          ????});
          ??},?[])

          ??//?useEffect?卸載函數(shù)會(huì)造成閉包問(wèn)題
          ??useEffect(()?=>?{
          ????return?()?=>?{
          ??????console.log(count);
          ????}
          ??},?[]);

          ??return?(
          ????<button
          ??????onClick={()?=>
          ?setCount(c?=>?c?+?1)}
          ????>
          ??????click
          ????button>

          ??)
          }

          在以上示例代碼中,四種情況均會(huì)出現(xiàn)閉包問(wèn)題,永遠(yuǎn)輸出 0。這四種情況的根因都是一樣的,我們看一下代碼的執(zhí)行順序:

          1. 組件初始化,此時(shí) count = 0
          2. 執(zhí)行 useEffect,此時(shí) useEffect 的函數(shù)執(zhí)行,JS 引用鏈記錄了對(duì) count=0 的引用關(guān)系
          3. 點(diǎn)擊 button,count 變化,但對(duì)之前的引用已經(jīng)無(wú)能為力了

          可以看到,閉包問(wèn)題均是出現(xiàn)在延遲調(diào)用的場(chǎng)景下。解決辦法如下:

          const?[count,?setCount]?=?useState(0);

          //?通過(guò)?ref?來(lái)記憶最新的?count
          const?countRef?=?useRef(count);
          countRef.current?=?count;

          useEffect(()?=>?{
          ??const?timer?=?setTimeout(()?=>?{
          ????console.log(countRef.current)
          ??},?3000);
          ??return?()?=>?{
          ????clearTimeout(timer);
          ??}
          },?[])

          ......

          通過(guò) useRef 來(lái)保證任何時(shí)候訪(fǎng)問(wèn)的 countRef.current 都是最新的,以解決閉包問(wèn)題。

          到這里,我重申下我對(duì) useEffect 的建議:

          1. 只有變化時(shí),需要重新執(zhí)行 useEffect 的變量,才要放到 deps 中。而不是 useEffect 用到的變量都放到 deps 中。
          2. 在有延遲調(diào)用場(chǎng)景時(shí),可以通過(guò) ref 來(lái)解決閉包問(wèn)題。

          3. 盡量不要用 useCallback

          我建議在項(xiàng)目中盡量不要用 useCallback,大部分場(chǎng)景下,不僅沒(méi)有提升性能,反而讓代碼可讀性變的很差。

          3.1 useCallback 大部分場(chǎng)景沒(méi)有提升性能

          useCallback 可以記住函數(shù),避免函數(shù)重復(fù)生成,這樣函數(shù)在傳遞給子組件時(shí),可以避免子組件重復(fù)渲染,提高性能。

          const?someFunc?=?useCallback(()=>?{
          ???doSomething();
          },?[]);

          return?<ExpensiveComponent?func={someFunc}?/>

          基于以上認(rèn)知,很多同學(xué)(包括我自己)在寫(xiě)代碼時(shí),只要是個(gè)函數(shù),都加個(gè) useCallback,是你么?反正我以前是。

          但我們要注意,提高性能還必須有另外一個(gè)條件,子組件必須使用了 shouldComponentUpdate 或者 React.memo 來(lái)忽略同樣的參數(shù)重復(fù)渲染。

          假如 ExpensiveComponent 組件只是一個(gè)普通組件,是沒(méi)有任何用的。比如下面這樣:

          const?ExpensiveComponent?=?({?func?})?=>?{
          ??return?(
          ????<div?onClick={func}>
          ?????hello
          ????div>

          ??)
          }

          必須通過(guò) React.memo 包裹 ExpensiveComponent ,才會(huì)避免參數(shù)不變的情況下的重復(fù)渲染,提高性能。

          const?ExpensiveComponent?=?React.memo(({?func?})?=>?{
          ??return?(
          ????<div?onClick={func}>
          ?????hello
          ????div>

          ??)
          })

          所以,useCallback 是要和 shouldComponentUpdate/React.memo 配套使用的,你用對(duì)了嗎?當(dāng)然,我建議一般項(xiàng)目中不用考慮性能優(yōu)化的問(wèn)題,也就是不要使用 useCallback 了,除非有個(gè)別非常復(fù)雜的組件,單獨(dú)使用即可。

          3.2 useCallback 讓代碼可讀性變差

          我看到過(guò)一些代碼,使用 useCallback 后,大概長(zhǎng)這樣:

          const?someFuncA?=?useCallback((d,?g,?x,?y)=>?{
          ???doSomething(a,?b,?c,?d,?g,?x,?y);
          },?[a,?b,?c]);

          const?someFuncB?=?useCallback(()=>?{
          ???someFuncA(d,?g,?x,?y);
          },?[someFuncA,?d,?g,?x,?y]);

          useEffect(()=>{
          ??someFuncB();
          },?[someFuncB]);

          在上面的代碼中,變量依賴(lài)一層一層傳遞,最終要判斷具體哪些變量變化會(huì)觸發(fā) useEffect 執(zhí)行,是一件很頭疼的事情。

          我期望不要用 useCallback,直接裸寫(xiě)函數(shù)就好:

          const?someFuncA?=?(d,?g,?x,?y)=>?{
          ???doSomething(a,?b,?c,?d,?g,?x,?y);
          };

          const?someFuncB?=?()=>?{
          ???someFuncA(d,?g,?x,?y);
          };

          useEffect(()=>{
          ??someFuncB();
          },?[...]);

          在 useEffect 存在延遲調(diào)用的場(chǎng)景下,可能造成閉包問(wèn)題,那通過(guò)咱們?nèi)f能的方法就能解決:

          const?someFuncA?=?(d,?g,?x,?y)=>?{
          ???doSomething(a,?b,?c,?d,?g,?x,?y);
          };

          const?someFuncB?=?()=>?{
          ???someFuncA(d,?g,?x,?y);
          };

          +?const?someFuncBRef?=?useRef(someFuncB);
          +?someFuncBRef.current?=?someFuncB;

          useEffect(()=>{
          +??setTimeout(()=>{
          +????someFuncBRef.current();
          +??},?1000)
          },?[...]);

          對(duì) useCallback 的建議就一句話(huà):沒(méi)事別用 useCallback。

          4. useMemo 建議適當(dāng)使用

          相較于 useCallback 而言,useMemo 的收益是顯而易見(jiàn)的。

          //?沒(méi)有使用?useMemo
          const?memoizedValue?=?computeExpensiveValue(a,?b);

          //?使用?useMemo
          const?memoizedValue?=?useMemo(()?=>?computeExpensiveValue(a,?b),?[a,?b]);

          如果沒(méi)有使用 useMemo,computeExpensiveValue 會(huì)在每一次渲染的時(shí)候執(zhí)行。如果使用了 useMemo,只有在 ab 變化時(shí),才會(huì)執(zhí)行一次 computeExpensiveValue

          這筆賬大家應(yīng)該都會(huì)算,所以我建議 useMemo 可以適當(dāng)使用。

          當(dāng)然也不是無(wú)節(jié)制的使用,在很簡(jiǎn)單的基礎(chǔ)類(lèi)型計(jì)算時(shí),可能 useMemo 并不劃算。

          const?a?=?1;
          const?b?=?2;

          const?c?=?useMemo(()=>?a?+?b,?[a,?b]);

          比如上面的例子,請(qǐng)問(wèn)計(jì)算 a+b 的消耗大?還是記錄 a/b ,并比較a/b 是否變化的消耗大?

          明顯 a+b 消耗更小。

          const?a?=?1;
          const?b?=?2;

          const?c?=?a?+?b;

          這筆賬大家可以自己算,我建議簡(jiǎn)單的基礎(chǔ)類(lèi)型計(jì)算,就不要用 useMemo 了~

          5. useState 的正確使用姿勢(shì)

          useState 應(yīng)該算最簡(jiǎn)單的一個(gè) Hooks,但在使用中,也有很多技巧可循,如果嚴(yán)格按照以下幾點(diǎn),代碼可維護(hù)性直接翻倍。

          5.1 能用其他狀態(tài)計(jì)算出來(lái)就不用單獨(dú)聲明狀態(tài)

          一個(gè) state 必須不能通過(guò)其它 state/props 直接計(jì)算出來(lái),否則就不用定義 state。

          const?SomeComponent?=?(props)?=>?{

          ??const?[source,?setSource]?=?useState([
          ??????{type:?'done',?value:?1},
          ??????{type:?'doing',?value:?2},
          ??])

          ??const?[doneSource,?setDoneSource]?=?useState([])
          ??const?[doingSource,?setDoingSource]?=?useState([])

          ??useEffect(()?=>?{
          ????setDoingSource(source.filter(item?=>?item.type?===?'doing'))
          ????setDoneSource(source.filter(item?=>?item.type?===?'done'))
          ??},?[source])

          ??return?(
          ????<div>
          ???????.....
          ????div>

          ??)
          }

          上面的示例中,變量 doneSourcedoingSource 可以通過(guò)變量 source 計(jì)算出來(lái),那就不要定義 doneSourcedoingSource 了!

          const?SomeComponent?=?(props)?=>?{

          ??const?[source,?setSource]?=?useState([
          ??????{type:?'done',?value:?1},
          ??????{type:?'doing',?value:?2},
          ????])

          ??const?doneSource?=?useMemo(()=>?source.filter(item?=>?item.type?===?'done'),?[source]);
          ??const?doingSource?=?useMemo(()=>?source.filter(item?=>?item.type?===?'doing'),?[source]);

          ??return?(
          ????<div>
          ???????.....
          ????div>

          ??)
          }

          一般在項(xiàng)目中此類(lèi)問(wèn)題都比較隱晦,層層傳遞,在 Code Review 中很難一眼看出。如果能把變量定義清楚,那事情就成功了一半。

          5.2 保證數(shù)據(jù)源唯一

          在項(xiàng)目中同一個(gè)數(shù)據(jù),保證只存儲(chǔ)在一個(gè)地方。

          不要既存在 redux 中,又在組件中定義了一個(gè) state 存儲(chǔ)。

          不要既存在父級(jí)組件中,又在當(dāng)前組件中定義了一個(gè) state 存儲(chǔ)。

          不要既存在 url query 中,又在組件中定義了一個(gè) state 存儲(chǔ)。

          function?SearchBox({?data?})?{
          ??const?[searchKey,?setSearchKey]?=?useState(getQuery('key'));

          ??const?handleSearchChange?=?e?=>?{
          ????const?key?=?e.target.value;
          ????setSearchKey(key);
          ????history.push(`/movie-list?key=${key}`);
          ??}

          ??return?(
          ??????<input
          ????????value={searchKey}
          ????????placeholder="Search..."
          ????????onChange={handleSearchChange}
          ??????/>

          ??);
          }

          在上面的示例中,searchKey 存儲(chǔ)在兩個(gè)地方,既在 url query 上,又定義了一個(gè) state。完全可以?xún)?yōu)化成下面這樣:

          function?SearchBox({?data?})?{
          ??const?searchKey?=?parse(localtion.search)?.key;

          ??const?handleSearchChange?=?e?=>?{
          ????const?key?=?e.target.value;
          ????history.push(`/movie-list?key=${key}`);
          ??}

          ??return?(
          ??????<input
          ????????value={searchKey}
          ????????placeholder="Search..."
          ????????onChange={handleSearchChange}
          ??????/>

          ??);
          }

          在實(shí)際項(xiàng)目開(kāi)發(fā)中,此類(lèi)問(wèn)題也是比較隱晦,編碼時(shí)應(yīng)注意。

          5.3 useState 適當(dāng)合并

          項(xiàng)目中有木有寫(xiě)過(guò)這樣的代碼:

          const?[firstName,?setFirstName]?=?useState();
          const?[lastName,?setLastName]?=?useState();
          const?[school,?setSchool]?=?useState();
          const?[age,?setAge]?=?useState();
          const?[address,?setAddress]?=?useState();

          const?[weather,?setWeather]?=?useState();
          const?[room,?setRoom]?=?useState();

          反正我最開(kāi)始是寫(xiě)過(guò),useState 拆分過(guò)細(xì),導(dǎo)致代碼中一大片 useState。

          我建議,同樣含義的變量可以合并成一個(gè) state,代碼可讀性會(huì)提升很多:

          const?[userInfo,?setUserInfo]?=?useState({
          ??firstName,
          ??lastName,
          ??school,
          ??age,
          ??address
          });

          const?[weather,?setWeather]?=?useState();
          const?[room,?setRoom]?=?useState();

          當(dāng)然這種方式我們?cè)谧兏兞繒r(shí),一定不要忘記帶上老的字段,比如我們只想修改 firstName

          setUserInfo(s=>?({
          ??...s,
          ??fristName,
          }))

          其實(shí)如果是 React Class 組件,state 是會(huì)自動(dòng)合并的:

          this.setState({
          ??firstName
          })

          在 Hooks 中,可以有這種用法嗎?其實(shí)是可以的,我們自己封裝一個(gè) Hooks 就可以,比如 ahooks 的 useSetState[3],就封裝了類(lèi)似的邏輯:

          const?[userInfo,?setUserInfo]?=?useSetState({
          ??firstName,
          ??lastName,
          ??school,
          ??age,
          ??address
          });

          //?自動(dòng)合并
          setUserInfo({
          ??firstName
          })

          我自己在項(xiàng)目中大量使用了 useSetState 來(lái)代替 useState,來(lái)管理復(fù)雜類(lèi)型的 state,媽媽更愛(ài)我了。

          6、總結(jié)

          作為資深的 React Hooks 用戶(hù),我很認(rèn)可 React Hooks 帶來(lái)的提效,這也是我這幾年完全擁抱 Hooks 的原因。同時(shí)我也越來(lái)越覺(jué)得 React Hooks 難駕馭,尤其隨著 React 18 的 concurrent mode 的到來(lái),不知道會(huì)帶來(lái)什么坑。

          最后再給大家三個(gè)建議:

          1. 可以多使用別人封裝好的高級(jí) Hooks 來(lái)提效,比如 ahooks[4] 庫(kù)(哈哈哈
          2. 可以多看看別人封裝好的 Hooks 源碼,加深對(duì) React Hooks 理解,比如 ahooks[5] 庫(kù)(哈哈哈
          3. 對(duì) hooks 感興趣,可以關(guān)注公眾號(hào):前端技術(shù)磚家

          參考資料

          [1]

          ahooks: https://github.com/alibaba/hooks

          [2]

          eslint-plugin-react-hooks: https://www.npmjs.com/package/eslint-plugin-react-hooks#installation

          [3]

          useSetState: https://ahooks.js.org/zh-CN/hooks/use-set-state

          [4]

          ahooks: https://github.com/alibaba/hooks

          [5]

          ahooks: https://github.com/alibaba/hooks


          瀏覽 29
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧洲一区二区在线 | 亚洲日韩一级 | 日韩AV在线 东京热 | 天天干天天干天天天干 | 影音先锋在线爱爱 |