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

          【第28期】一文學(xué)會(huì)使用React Hooks

          共 13234字,需瀏覽 27分鐘

           ·

          2023-10-28 01:56

          概述

          React Hooks是React 16.8版本引入的一項(xiàng)新特性,它可以讓開發(fā)者在無(wú)需編寫類組件的情況下,使用狀態(tài)和其他React特性。

          • 使用React Hooks,開發(fā)者可以在函數(shù)組件中使用狀態(tài)(state)、副作用(side effects)和上下文(context),而不再需要編寫類組件。這樣可以使代碼更簡(jiǎn)潔、易于理解和測(cè)試。

          • React Hooks提供了一些預(yù)定義的鉤子函數(shù),如useState、useEffect、useContext等,開發(fā)者可以通過調(diào)用這些鉤子函數(shù)來(lái)使用相應(yīng)的特性。

          React Hooks具特點(diǎn)

          React Hooks提供了一種更簡(jiǎn)單、更直觀的方式來(lái)編寫React組件。它使得狀態(tài)管理、副作用處理和上下文使用更加簡(jiǎn)單和可靠,并提供了性能優(yōu)化和生命周期簡(jiǎn)化的特性。使用React Hooks可以提高開發(fā)效率、代碼可讀性和可維護(hù)性。

          函數(shù)式組件

          React Hooks允許在函數(shù)組件中使用狀態(tài)和其他React特性,而不再需要編寫類組件。這使得組件的代碼更簡(jiǎn)潔、易于理解和測(cè)試。

          狀態(tài)管理

          useState鉤子函數(shù)使得在函數(shù)組件中使用狀態(tài)變得非常簡(jiǎn)單。它返回一個(gè)狀態(tài)值和一個(gè)更新該狀態(tài)值的函數(shù),開發(fā)者可以直接在函數(shù)組件中聲明和使用狀態(tài)。

          副作用處理

          useEffect鉤子函數(shù)用于處理副作用,如訂閱事件、網(wǎng)絡(luò)請(qǐng)求等。它可以在組件渲染后執(zhí)行副作用操作,并在組件卸載前清理副作用。這使得副作用的管理更加簡(jiǎn)單和可靠。

          上下文使用

          useContext鉤子函數(shù)使得在函數(shù)組件中使用上下文變得容易。開發(fā)者可以訪問由React的Context API提供的上下文值,而不再需要使用高階組件或渲染屬性模式。

          可重用性

          useRef鉤子函數(shù)用于在函數(shù)組件中創(chuàng)建可變的引用。它可以用來(lái)保存任意可變值,類似于類組件中的實(shí)例變量。這使得在函數(shù)組件中實(shí)現(xiàn)一些需要保持狀態(tài)的邏輯更加方便。

          性能優(yōu)化

          useMemo和useCallback鉤子函數(shù)用于在函數(shù)組件中緩存計(jì)算結(jié)果和回調(diào)函數(shù)。它們可以避免重復(fù)計(jì)算和回調(diào)函數(shù)的重復(fù)創(chuàng)建,提高性能。

          簡(jiǎn)化生命周期

          React Hooks簡(jiǎn)化了組件的生命周期管理。不再需要編寫繁瑣的生命周期方法,Hooks提供了更直觀和靈活的方式來(lái)處理組件的行為。

          常用的React Hooks

          React Hooks是React的一項(xiàng)重要特性,它為開發(fā)者提供了更多的靈活性和便利性,使得開發(fā)React應(yīng)用更加簡(jiǎn)單和高效。使用React Hooks可以讓開發(fā)者更自由地組織代碼,避免類組件中的繁瑣的生命周期方法,并提供更好的性能和可測(cè)試性。但需要注意的是,Hooks只能在函數(shù)組件的頂層調(diào)用,不能在循環(huán)、條件語(yǔ)句或嵌套函數(shù)中調(diào)用。React Hooks包括以下常用的函數(shù):

          useState

          用于在函數(shù)組件中定義和更新狀態(tài)。用于在函數(shù)組件中使用狀態(tài)。它返回一個(gè)狀態(tài)值和一個(gè)更新該狀態(tài)值的函數(shù)。

          以下是一個(gè)使用useState的案例:

          import React, { useState } from 'react';
          function Counter() {
          const [count, setCount] = useState(0);
          return (
          <div>
          <h1>Count: {count}</h1>
          <button onClick={() => setCount(count + 1)}>Increment</button>
          <button onClick={() => setCount(count - 1)}>Decrement</button>
          </div>
          );
          }
          export default Counter;
          • 在上述例子中,我們使用了useState鉤子函數(shù)來(lái)聲明一個(gè)名為count的狀態(tài)變量和一個(gè)名為setCount的函數(shù),用于更新該狀態(tài)變量。
          • 在Counter組件中,我們將count的初始值設(shè)置為0。然后,我們?cè)诮M件的返回值中使用count來(lái)展示當(dāng)前的計(jì)數(shù)值,并使用setCount來(lái)更新該計(jì)數(shù)值。
          • 通過點(diǎn)擊"Increment"按鈕,我們調(diào)用setCount函數(shù)并傳入count + 1,從而將計(jì)數(shù)值增加1。同樣,點(diǎn)擊"Decrement"按鈕,我們調(diào)用setCount函數(shù)并傳入count - 1,從而將計(jì)數(shù)值減少1。
          • 每次調(diào)用setCount函數(shù)時(shí),React會(huì)重新渲染組件,并更新展示的計(jì)數(shù)值。

          這個(gè)例子展示了如何使用useState來(lái)在函數(shù)組件中管理狀態(tài)。useState返回的狀態(tài)值和更新函數(shù)可以在組件的其他地方使用,使得狀態(tài)的管理變得非常簡(jiǎn)單和直觀。

          useEffect

          用于在函數(shù)組件中執(zhí)行副作用操作,比如訂閱事件、發(fā)送網(wǎng)絡(luò)請(qǐng)求等。可以在組件渲染后執(zhí)行副作用操作,并在組件卸載前清理副作用。

          以下是一個(gè)使用React Hooks的useEffect的示例:

          import React, { useState, useEffect } from 'react';
          const App = () => {
          const [count, setCount] = useState(0);
          useEffect(() => {
          document.title = `Count: ${count}`;
          }, [count]);
          return (
          <div>
          <p>Count: {count}</p>
          <button onClick={() => setCount(count + 1)}>Increment</button>
          </div>
          );
          };
          export default App;
          • 在這個(gè)例子中,我們使用useState來(lái)創(chuàng)建一個(gè)名為count的狀態(tài)變量,并使用setCount函數(shù)來(lái)更新它的值。然后,我們使用useEffect來(lái)監(jiān)視count變量的變化,并在count變化時(shí)更新文檔標(biāo)題。每當(dāng)用戶點(diǎn)擊“Increment”按鈕時(shí),count的值會(huì)增加1,然后useEffect會(huì)觸發(fā),更新文檔標(biāo)題。

          • 這是一個(gè)簡(jiǎn)單的例子,但它展示了useEffect的用法:在組件渲染后執(zhí)行副作用操作。在這個(gè)例子中,副作用操作是更新文檔標(biāo)題,但useEffect還可以用于執(zhí)行其他副作用操作,例如發(fā)送網(wǎng)絡(luò)請(qǐng)求、訂閱事件等。

          useContext

          用于在函數(shù)組件中訪問共享的狀態(tài),而不需要通過props傳遞。用于在函數(shù)組件中使用上下文。可以訪問由React的Context API提供的上下文值。

          以下是一個(gè)使用React Hooks的useContext的示例:

          import React, { useState, useContext, createContext } from 'react';
          // 創(chuàng)建一個(gè)上下文對(duì)象
          const ThemeContext = createContext();
          // 父組件
          const App = () => {
          const [theme, setTheme] = useState('light');
          return (
          <ThemeContext.Provider value={{ theme, setTheme }}>
          <Toolbar />
          </ThemeContext.Provider>
          );
          };
          // 子組件
          const Toolbar = () => {
          const { theme, setTheme } = useContext(ThemeContext);
          const toggleTheme = () => {
          setTheme(theme === 'light' ? 'dark' : 'light');
          };
          return (
          <div>
          <button onClick={toggleTheme}>Toggle Theme</button>
          <p>Current Theme: {theme}</p>
          </div>
          );
          };
          export default App;
          • 在這個(gè)例子中,我們使用createContext創(chuàng)建了一個(gè)名為ThemeContext的上下文對(duì)象。然后,我們?cè)诟附M件App中使用useState創(chuàng)建了一個(gè)名為theme的狀態(tài)變量,并使用setTheme函數(shù)來(lái)更新它的值。將theme和setTheme通過ThemeProvider提供給子組件。

          • 在子組件Toolbar中,我們使用useContext來(lái)獲取ThemeContext的值,即theme和setTheme。然后,我們?cè)趖oggleTheme函數(shù)中根據(jù)當(dāng)前的theme值來(lái)切換主題。當(dāng)用戶點(diǎn)擊“Toggle Theme”按鈕時(shí),theme的值會(huì)切換為“l(fā)ight”或“dark”,并通過setTheme函數(shù)更新。然后,我們?cè)诮缑嫔巷@示當(dāng)前的主題。

          • 這個(gè)例子展示了useContext的用法:通過創(chuàng)建和使用上下文對(duì)象,我們可以在組件之間共享數(shù)據(jù)和函數(shù),而不需要通過props傳遞。

          useReducer

          類似于useState,但可以處理復(fù)雜的狀態(tài)邏輯。

          以下是一個(gè)使用React Hooks的useReducer的示例:

          import React, { useReducer } from 'react';
          // 初始化狀態(tài)
          const initialState = { count: 0 };
          // reducer函數(shù)
          const reducer = (state, action) => {
          switch (action.type) {
          case 'increment':
          return { count: state.count + 1 };
          case 'decrement':
          return { count: state.count - 1 };
          default:
          throw new Error();
          }
          };
          // 組件
          const Counter = () => {
          const [state, dispatch] = useReducer(reducer, initialState);
          return (
          <div>
          <p>Count: {state.count}</p>
          <button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
          <button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
          </div>
          );
          };
          export default Counter;
          • 在這個(gè)例子中,我們使用useReducer來(lái)創(chuàng)建一個(gè)名為state的狀態(tài)變量和一個(gè)名為dispatch的函數(shù)。useReducer接收一個(gè)reducer函數(shù)和一個(gè)初始狀態(tài)initialState作為參數(shù)。reducer函數(shù)根據(jù)action的類型來(lái)更新狀態(tài),并返回一個(gè)新的狀態(tài)對(duì)象。

          • 在組件中,我們顯示了當(dāng)前的計(jì)數(shù)值state.count,并使用dispatch函數(shù)來(lái)分發(fā)不同的action。當(dāng)用戶點(diǎn)擊“Increment”按鈕時(shí),我們使用dispatch({ type: 'increment' })來(lái)觸發(fā)一個(gè)increment類型的action,reducer函數(shù)會(huì)將計(jì)數(shù)值加1。當(dāng)用戶點(diǎn)擊“Decrement”按鈕時(shí),我們使用dispatch({ type: 'decrement' })來(lái)觸發(fā)一個(gè)decrement類型的action,reducer函數(shù)會(huì)將計(jì)數(shù)值減1。

          • 這個(gè)例子展示了useReducer的用法:通過reducer函數(shù)和dispatch函數(shù),我們可以在組件中管理復(fù)雜的狀態(tài)邏輯。在這個(gè)例子中,我們使用useReducer來(lái)管理計(jì)數(shù)器的狀態(tài),但它也可以用于管理更復(fù)雜的狀態(tài),例如表單數(shù)據(jù)、列表數(shù)據(jù)等。

          useRef

          用于在函數(shù)組件中創(chuàng)建可變的引用。可以用來(lái)保存任意可變值,類似于類組件中的實(shí)例變量。

          以下是一個(gè)使用React Hooks的useRef的示例:

          import React, { useRef } from 'react';
          const TextInput = () => {
          const inputRef = useRef();
          const handleFocus = () => {
          inputRef.current.focus();
          };
          return (
          <div>
          <input ref={inputRef} type="text" />
          <button onClick={handleFocus}>Focus</button>
          </div>
          );
          };
          export default TextInput;
          • 在這個(gè)例子中,我們使用useRef來(lái)創(chuàng)建一個(gè)名為inputRef的引用。在組件中,我們將input元素的ref屬性設(shè)置為inputRef,這樣我們就可以通過inputRef.current來(lái)訪問input元素。

          • 在handleFocus函數(shù)中,我們使用inputRef.current.focus()來(lái)聚焦input元素。當(dāng)用戶點(diǎn)擊“Focus”按鈕時(shí),handleFocus函數(shù)會(huì)被調(diào)用,從而將焦點(diǎn)設(shè)置到input元素上。

          這個(gè)例子展示了useRef的用法:通過引用,我們可以在函數(shù)組件中獲取和操作DOM元素。在這個(gè)例子中,我們使用useRef來(lái)獲取input元素,并通過引用來(lái)聚焦該元素。除了DOM元素,useRef還可以用于存儲(chǔ)和訪問任意的可變值,類似于類組件中的實(shí)例變量。

          useMemo

          用于在函數(shù)組件中緩存計(jì)算結(jié)果。可以避免重復(fù)計(jì)算,提高性能,以優(yōu)化性能。

          以下是一個(gè)使用React Hooks的useMemo的示例:

          import React, { useState, useMemo } from 'react';
          const ExpensiveCalculation = () => {
          // 假設(shè)這是一個(gè)昂貴的計(jì)算函數(shù)
          const calculate = (a, b) => {
          console.log('Calculating...');
          return a + b;
          };
          const [num1, setNum1] = useState(0);
          const [num2, setNum2] = useState(0);
          // 使用useMemo來(lái)緩存計(jì)算結(jié)果
          const result = useMemo(() => calculate(num1, num2), [num1, num2]);
          return (
          <div>
          <input type="number" value={num1} onChange={(e) => setNum1(Number(e.target.value))} />
          <input type="number" value={num2} onChange={(e) => setNum2(Number(e.target.value))} />
          <p>Result: {result}</p>
          </div>
          );
          };
          export default ExpensiveCalculation;
          • 在這個(gè)例子中,我們假設(shè)calculate函數(shù)是一個(gè)昂貴的計(jì)算函數(shù),它接收兩個(gè)參數(shù)并返回它們的和。我們使用useState來(lái)創(chuàng)建兩個(gè)狀態(tài)變量num1和num2,分別表示兩個(gè)輸入框中的值。

          • 然后,我們使用useMemo來(lái)緩存計(jì)算結(jié)果。useMemo接收一個(gè)回調(diào)函數(shù)和一個(gè)依賴數(shù)組,只有當(dāng)依賴數(shù)組中的值發(fā)生變化時(shí),才會(huì)重新計(jì)算回調(diào)函數(shù)的結(jié)果。在這個(gè)例子中,我們將calculate函數(shù)和num1、num2作為依賴數(shù)組,這樣只有當(dāng)num1或num2的值發(fā)生變化時(shí),才會(huì)重新計(jì)算calculate的結(jié)果。

          • 最后,我們?cè)诮缑嫔巷@示計(jì)算結(jié)果result。

          這個(gè)例子展示了useMemo的用法:通過緩存計(jì)算結(jié)果,我們可以避免在每次渲染時(shí)都執(zhí)行昂貴的計(jì)算操作。在這個(gè)例子中,我們使用useMemo來(lái)緩存計(jì)算結(jié)果,以提高性能。

          useCallback

          用于在函數(shù)組件中緩存回調(diào)函數(shù)。可以避免回調(diào)函數(shù)的重復(fù)創(chuàng)建,提高性能,以優(yōu)化性能。

          以下是一個(gè)使用React Hooks的useCallback的示例:

          import React, { useState, useCallback } from 'react';
          const Button = () => {
          const [count, setCount] = useState(0);
          // 使用useCallback來(lái)緩存回調(diào)函數(shù)
          const handleClick = useCallback(() => {
          setCount(count + 1);
          }, [count]);
          return (
          <div>
          <p>Count: {count}</p>
          <button onClick={handleClick}>Increment</button>
          </div>
          );
          };
          export default Button;
          • 在這個(gè)例子中,我們使用useState來(lái)創(chuàng)建一個(gè)名為count的狀態(tài)變量,表示計(jì)數(shù)值。

          • 然后,我們使用useCallback來(lái)緩存回調(diào)函數(shù)handleClick。useCallback接收一個(gè)回調(diào)函數(shù)和一個(gè)依賴數(shù)組,只有當(dāng)依賴數(shù)組中的值發(fā)生變化時(shí),才會(huì)重新創(chuàng)建回調(diào)函數(shù)。在這個(gè)例子中,我們將count作為依賴數(shù)組,這樣只有當(dāng)count的值發(fā)生變化時(shí),才會(huì)重新創(chuàng)建handleClick回調(diào)函數(shù)。

          • 最后,我們?cè)诮缑嫔巷@示計(jì)數(shù)值count,并將handleClick回調(diào)函數(shù)綁定到按鈕的onClick事件。

          這個(gè)例子展示了useCallback的用法:通過緩存回調(diào)函數(shù),我們可以避免在每次渲染時(shí)都創(chuàng)建新的回調(diào)函數(shù)。在這個(gè)例子中,我們使用useCallback來(lái)緩存handleClick回調(diào)函數(shù),以提高性能。

          useLayoutEffect

          類似于useEffect,但在DOM更新之后同步執(zhí)行,用于處理DOM操作的副作用。使用useLayoutEffect的一個(gè)常見案例是在DOM渲染完成后執(zhí)行一些副作用操作,例如更新DOM元素的位置或大小。

          下面是一個(gè)使用useLayoutEffect的示例:

          import React, { useState, useLayoutEffect } from 'react';
          const MyComponent = () => {
          const [width, setWidth] = useState(0);
          useLayoutEffect(() => {
          const handleResize = () => {
          setWidth(window.innerWidth);
          };
          // 添加resize事件監(jiān)聽器
          window.addEventListener('resize', handleResize);
          // 初始化時(shí)獲取一次窗口寬度
          handleResize();
          // 清除resize事件監(jiān)聽器
          return () => {
          window.removeEventListener('resize', handleResize);
          };
          }, []);
          return <div>窗口寬度: {width}px</div>;
          };
          export default MyComponent;
          • 在上面的示例中,useLayoutEffect鉤子被用來(lái)在組件渲染后添加一個(gè)resize事件監(jiān)聽器,并在組件卸載前清除監(jiān)聽器。在handleResize回調(diào)函數(shù)中,通過調(diào)用setWidth來(lái)更新組件的狀態(tài),從而觸發(fā)重新渲染。

          • 這個(gè)例子中,我們使用了一個(gè)空的依賴數(shù)組作為useLayoutEffect的第二個(gè)參數(shù),這意味著只有在組件初始化時(shí)才會(huì)執(zhí)行一次useLayoutEffect的回調(diào)函數(shù)。這樣我們就可以確保只添加一次resize事件監(jiān)聽器,并且在組件卸載時(shí)正確地清除它。

          • 通過使用useLayoutEffect來(lái)處理副作用操作,我們可以確保在DOM渲染完成后執(zhí)行這些操作,從而避免可能導(dǎo)致布局問題的延遲效果。

          useImperativeHandle

          用于在父組件中訪問子組件的方法和屬性。使用useImperativeHandle的一個(gè)常見案例是在子組件中暴露父組件的某些方法或?qū)傩裕员愀附M件可以直接調(diào)用子組件的方法或訪問子組件的屬性。

          下面是一個(gè)使用useImperativeHandle的示例:

          import React, { useRef, useImperativeHandle, forwardRef } from 'react';
          const ChildComponent = forwardRef((props, ref) => {
          const inputRef = useRef(null);
          useImperativeHandle(ref, () => ({
          focusInput: () => {
          inputRef.current.focus();
          },
          getValue: () => {
          return inputRef.current.value;
          }
          }));
          return <input ref={inputRef} />;
          });
          const ParentComponent = () => {
          const childRef = useRef(null);
          const handleClick = () => {
          childRef.current.focusInput();
          };
          const handleGetValue = () => {
          const value = childRef.current.getValue();
          console.log('子組件的值:', value);
          };
          return (
          <div>
          <ChildComponent ref={childRef} />
          <button onClick={handleClick}>聚焦子組件輸入框</button>
          <button onClick={handleGetValue}>獲取子組件的值</button>
          </div>
          );
          };
          export default ParentComponent;
          • 在上面的示例中,我們使用useRef來(lái)創(chuàng)建一個(gè)引用,然后將其傳遞給子組件的ref屬性。在子組件中,我們使用useImperativeHandle來(lái)定義父組件可以調(diào)用的方法或訪問的屬性。在這個(gè)例子中,我們暴露了一個(gè)focusInput方法和一個(gè)getValue方法,分別用于聚焦子組件的輸入框和獲取輸入框的值。

          • 在父組件中,我們可以通過調(diào)用childRef.current.focusInput()來(lái)聚焦子組件的輸入框,或者通過調(diào)用childRef.current.getValue()來(lái)獲取子組件輸入框的值。

          • 通過使用useImperativeHandle,我們可以更靈活地在父組件中操作子組件,同時(shí)保持良好的封裝性。這在需要直接與子組件進(jìn)行交互的情況下非常有用。

          useDebugValue

          用于在React開發(fā)者工具中顯示自定義的鉤子名稱。使用useDebugValue的一個(gè)常見案例是在自定義的Hook中為開發(fā)者提供更好的調(diào)試工具,例如在React開發(fā)者工具中顯示有用的自定義標(biāo)簽。

          下面是一個(gè)使用useDebugValue的示例:

          import React, { useState, useEffect, useDebugValue } from 'react';
          const useFetchData = (url) => {
          const [data, setData] = useState(null);
          const [loading, setLoading] = useState(true);
          useEffect(() => {
          const fetchData = async () => {
          try {
          const response = await fetch(url);
          const json = await response.json();
          setData(json);
          setLoading(false);
          } catch (error) {
          console.error(error);
          }
          };
          fetchData();
          }, [url]);
          // 使用useDebugValue在React開發(fā)者工具中顯示自定義標(biāo)簽
          useDebugValue(loading ? 'Loading...' : data ? 'Data loaded' : 'No data');
          return { data, loading };
          };
          const MyComponent = () => {
          const { data, loading } = useFetchData('https://api.example.com/data');
          if (loading) {
          return <div>Loading...</div>;
          }
          if (!data) {
          return <div>No data available</div>;
          }
          return (
          <div>
          {data.map((item) => (
          <div key={item.id}>{item.name}</div>
          ))}
          </div>
          );
          };
          export default MyComponent;
          • 在上面的示例中,我們創(chuàng)建了一個(gè)自定義的Hook useFetchData,它會(huì)從指定的URL獲取數(shù)據(jù)并返回?cái)?shù)據(jù)和加載狀態(tài)。在useFetchData中,我們使用了useDebugValue來(lái)為開發(fā)者提供有用的調(diào)試信息。在React開發(fā)者工具中,我們可以看到loading狀態(tài)是"Loading..."、data狀態(tài)是"Data loaded"或者是"No data"。

          • 通過使用useDebugValue,我們可以更好地了解Hook在不同狀態(tài)下的運(yùn)行情況,以及為開發(fā)者提供更好的調(diào)試工具。這對(duì)于自定義Hook的開發(fā)和調(diào)試非常有幫助。

          除了上述常用的Hooks,還可以通過自定義Hooks來(lái)實(shí)現(xiàn)更多的功能和復(fù)用邏輯。自定義Hooks可以使用任何已有的Hooks,并以"use"開頭命名,以便于其他開發(fā)者識(shí)別和使用。

          關(guān)注我們

          - END -

          瀏覽 82
          點(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>
                  西西444 | 俺也来俺也去WWW色 | 91成人在线电影 | 免费中文字幕日韩欧美 | 免费观看日本污的视频 |