React Hooks 實現一個搜索功能

react 實現一個搜索功能

  • 要求實時搜索,獲得結果,結果由接口數據返回
  • 實現圖

image

來先用基本的 react 實現一個吧

import stores from './stores' // 事先準備好的接口庫
import _ from 'loadsh'; // 使用 debounce,實時獲得接口須要 debounce 

class Search extend Component{
    featchList = async (val = '')=>{
        try{
            const data = await stores.featchList(val);
            
            data && this.setState({
                data
            })
        }catch(err){
            throw(err)
        }
    }

    handleOnSearch = (ev)=>{
        console.log(ev);
        
        this.featchList(ev.target.value)
    }
    
    componentDidMount(){
        this.featchList();
    }
    
    render(){
        <div className="search-container">
            <input onChange={_.debounce(ev => this.handleOnSearch(ev), 300)}/> <div className="list"> {this.state.data} </div> </div>
    }
}
複製代碼

如上一個簡單的實時輸入搜索,而後300ms延時展現結果的react就完成了,咱們怎麼使用 hooks 改裝一下啦?html

小知識 useEffect

  • useEffect(cakkBackFunc, array)
cakkBackFunc 能夠返回一個函數,用做清理

array(可選參數):數組,用於控制useEffect的執行
* 分三種狀況
    《1》空數組,則只會執行一次(即初次渲染render),至關於componentDidMount
    《2》非空數組,useEffect會在數組發生變化後執行
    《3》不填array這個數組,useEffect每次渲染都會執行
複製代碼

hooks 的現實搜索功能

function App() {
  const [data, setData] = useState([]);
  const [query, setQuery] = useState('');

  useEffect(() => {
    const featchList = async (query = '')=>{
        try{
            const data = await stores.featchList(query);
            
            data && setData(data);
        }catch(err){
            throw err;
        }
    }

    featchList(query); // 咱們把 query 當作參數傳進去,把data和query 聯動起來這樣就能夠達到搜索的功能啦。
  }, []);

  return (
    <div className="search-container"> <input onChange={_.debounce(ev => setQuery(ev.target.value), 300)}/> <div className="list"> {this.state.data} </div> </div> ); } export default App; 複製代碼
  • 咱們可能會遇到相關問題: react 會報錯下面插件的相關 warning
咱們提供了一個 `exhaustive-deps ESLint` 規則做爲 `eslint-plugin-react-hooks`
包的一部分。它會幫助你找出沒法一致地處理更新的組件。
複製代碼

試試上面的代碼,發現如今只實現了 componentDidMount 中一次 mount的數據獲取,咱們在輸入 input 框的時候並無去請求新的數據,這個時候咱們就須要在 useEffect(a,b) 的第二個參數中放入 [query],當他發生變化的時候再從新觸發 useEffect()react

function App() {
  const [data, setData] = useState([]);
  const [query, setQuery] = useState('');

  useEffect(() => {
    const featchList = async (query = '')=>{
        try{
            const data = await stores.featchList(query);
            
            data && setData(data);
        }catch(err){
            throw err;
        }
    }

    featchList(query); // 咱們把 query 當作參數傳進去,把data和query 聯動起來這樣就能夠達到搜索的功能啦。
  }, [query]); // 隨着 query 的變化,從新 mount,獲取新的搜索的數據

  return (
    ....
  );
}

export default App;
複製代碼

一個衍生問題?-- 在依賴列表中省略函數是否安全?

  • 這裏可能有同窗會問了,咱們爲何要把 featchList 定義到 useEffect() 內部?直接和之前的寫法同樣放在外面有什麼區別嗎?json

  • 咱們來看這句話 ==若是你指定了一個 依賴列表 做爲 useEffect、useMemo、useCallback 或 useImperativeHandle 的最後一個參數,它必須包含參與那次 React 數據流的全部值。這就包含了 props、state,以及任何由它們衍生而來的東西。==segmentfault

function ProductPage({ productId }) {
  const [product, setProduct] = useState(null);

  async function fetchProduct() {
    const response = await fetch('http://myapi/product' + productId); // 使用了 productId prop
    const json = await response.json();
    setProduct(json);
  }

  useEffect(() => {
    fetchProduct();
  }, []); // 🔴 這樣是無效的,由於 `fetchProduct` 使用了 `productId`
  // ...
}
複製代碼
  • 解決方案: 推薦的修復方案是把那個函數移動到你的 effect 內部。這樣就能很容易的看出來你的 effect 使用了哪些 props 和 state
function ProductPage({ productId }) {
  const [product, setProduct] = useState(null);

  useEffect(() => {
    // 把這個函數移動到 effect 內部後,咱們能夠清楚地看到它用到的值。
    async function fetchProduct() {
      const response = await fetch('http://myapi/product' + productId);
      const json = await response.json();
      setProduct(json);
    }

    fetchProduct();
  }, [productId]); // ✅ 有效,由於咱們的 effect 只用到了 productId
  // ...
}
複製代碼

總結,若是使用了props,state,或者他們的衍生值,咱們須要把相關使用的函數放進 useEffect 中,而後把相關值放進 useEffect 的第二個參數中api

參考

相關文章
相關標籤/搜索