本文共 10920 字,大约阅读时间需要 36 分钟。
阅读前提:希望你对react-hook的官方文档有几次阅读。
下面我基本是拿了人家的代码直接过来自己执行。该骂看起来不难,重要的是人家的思路值得学习。 如果想看原味的请移步这里,仔细看完你会觉得太美了。
下面的代码是封装类似于useHttp的自定义hook。
import React, { useState } from 'react';function App() { const [data, setData] = useState({ hits: [] }); return (
axios最基本的使用
import React, { useState, useEffect } from 'react';import axios from 'axios’;function App() { const [data, setData] = useState({ hits: [] }); useEffect(async () => { const result = await axios( 'http://hn.algolia.com/api/v1/search?query=redux', ); setData(result.data); }); return (
可以替代原来react生命周期的componentDidMount
。
useEffect(async () => { const result = await axios( 'http://hn.algolia.com/api/v1/search?query=redux', ); setData(result.data);}, []); // 每次传递一个空数组 只有第一次初始化组件的时候 才会渲染复制代码
组件执行的时候会报错 因为 useEffect不支持async异步的函数
修改之后
useEffect(() => { const fetchData = async () => { const result = await axios( 'http://hn.algolia.com/api/v1/search?query=redux', ); setData(result.data); }; fetchData();}, []);复制代码
hook函数已经替代
componentDidMount
这个生命周期函数钩子
如何去触发hook这个钩子函数
当query
发生变化的时候 自动发送请求
import React, { Fragment, useState, useEffect } from 'react';import axios from 'axios';function App() { const [data, setData] = useState({ hits: [] }); const [query, setQuery] = useState('redux'); useEffect(() => { const fetchData = async () => { const result = await axios( 'http://hn.algolia.com/api/v1/search?query=redux', ); setData(result.data); }; fetchData(); }, []); return (setQuery(event.target.value)} /> );}export default App;复制代码{data.hits.map(item => (
- {item.title}
))}
执行一次
useEffect(() => { const fetchData = async () => { const result = await axios( `http://hn.algolia.com/api/v1/search?query=${query}`, ); setData(result.data); },[])复制代码
现在 当我们在input输入文字的时候 需要触发这个钩子函数 useEffect的第二个参数 中的state发生变化的时候 就会自动触发该钩子函数重新执行一次
useEffect(() => { const fetchData = async () => { const result = await axios( `http://hn.algolia.com/api/v1/search?query=${query}`, ); setData(result.data); },[query]) // 添加需要触发这个钩子的state复制代码
只要query发生变化。这个函数就会重新执行 现在已经实现每次输入一个字符 就会发送一个请求
接下来需要 添加一个按钮 去获取input输入的字符 然后点击按钮的时候去触发useEffect
function App() { const [data, setData] = useState({ hits: [] }); const [query, setQuery] = useState('redux’); const [search, setSearch] = useState(''); useEffect(() => { const fetchData = async () => { const result = await axios( `http://hn.algolia.com/api/v1/search?query=${query}`, ); setData(result.data); }; fetchData(); }, [query]); return (setQuery(event.target.value)} /> );}复制代码{data.hits.map(item => (
- {item.title}
))}
每次input输入的时候 会触发query的变化。button点击的时候
将query设置成 search
useEffect(() => { const fetchData = async () => { const result = await axios( `http://hn.algolia.com/api/v1/search?query=${search}`, ); setData(result.data); }; fetchData();}, [search]);复制代码
现在只有search发生变化的时候 才会触发useEffect触发 search要触发的话 只有点击button的时候才能获取
此处将URL单独提取出来
function App() { const [data, setData] = useState({ hits: [] }); const [query, setQuery] = useState('redux'); const [url, setUrl] = useState( 'http://hn.algolia.com/api/v1/search?query=redux', ); useEffect(() => { const fetchData = async () => { const result = await axios(url); setData(result.data); }; fetchData(); }, [url]); return (setQuery(event.target.value)} /> );}复制代码{data.hits.map(item => (
- {item.title}
))}
请求之前进行loadding的设置 并且渲染到ui中
import React, { Fragment, useState, useEffect } from 'react';import axios from 'axios';function App() { const [data, setData] = useState({ hits: [] }); const [query, setQuery] = useState('redux'); const [url, setUrl] = useState( 'http://hn.algolia.com/api/v1/search?query=redux', ); const [isLoading, setIsLoading] = useState(false); useEffect(() => { const fetchData = async () => { setIsLoading(true); const result = await axios(url); setData(result.data); setIsLoading(false); }; fetchData(); }, [url]); return (setQuery(event.target.value)} /> {isLoading ? ( );}export default App;复制代码Loading ...) : ({data.hits.map(item => (
)}- {item.title}
))}
import React, { Fragment, useState, useEffect } from 'react';import axios from 'axios';function App() { const [data, setData] = useState({ hits: [] }); const [query, setQuery] = useState('redux'); const [url, setUrl] = useState( 'http://hn.algolia.com/api/v1/search?query=redux', ); const [isLoading, setIsLoading] = useState(false); const [isError, setIsError] = useState(false); useEffect(() => { const fetchData = async () => { setIsError(false); setIsLoading(true); try { const result = await axios(url); setData(result.data); } catch (error) { setIsError(true); } setIsLoading(false); }; fetchData(); }, [url]); return (setQuery(event.target.value)} /> {isError && );}export default App;复制代码Something went wrong ...} {isLoading ? (Loading ...) : ({data.hits.map(item => (
)}- {item.title}
))}
{isError && 复制代码Something went wrong ...} …
阻止默认
的表单提交动作const useHackerNewsApi = () => { const [data, setData] = useState({ hits: [] }); const [url, setUrl] = useState( 'http://hn.algolia.com/api/v1/search?query=redux', ); const [isLoading, setIsLoading] = useState(false); const [isError, setIsError] = useState(false); useEffect(() => { const fetchData = async () => { setIsError(false); setIsLoading(true); try { const result = await axios(url); setData(result.data); } catch (error) { setIsError(true); } setIsLoading(false); }; fetchData(); }, [url]); return [{ data, isLoading, isError }, setUrl];}复制代码
function App() { const [query, setQuery] = useState('redux'); const [{ data, isLoading, isError }, doFetch] = useHackerNewsApi(); return (... );}复制代码
function App() { const [query, setQuery] = useState('redux'); const [{ data, isLoading, isError }, doFetch] = useDataApi( 'http://hn.algolia.com/api/v1/search?query=redux', { hits: [] }, );...const useDataApi = (initialUrl, initialData) => { const [data, setData] = useState(initialData); const [url, setUrl] = useState(initialUrl);...复制代码
使用Reducer Hook来提取数据
在useEffect中多次设置state的状态, 不方便调整。使用reduce将整个数据的状态进行集中管理设置
import React, { Fragment, useState, useEffect, useReducer, // 引入usrReducer} from 'react';import axios from 'axios';const dataFetchReducer = (state, action) => { // 定义useReducer触发函数...};const useDataApi = (initialUrl, initialData) => { const [url, setUrl] = useState(initialUrl); const [state, dispatch] = useReducer(dataFetchReducer, { // 使用useReducer isLoading: false, isError: false, data: initialData, });...};复制代码
useEffect(() => { const fetchData = async () => { dispatch({ type: 'FETCH_INIT' }); // 使用dispatch派发设置state try { const result = await axios(url); dispatch({ type: 'FETCH_SUCCESS', payload: result.data }); } catch (error) { dispatch({ type: 'FETCH_FAILURE' }); } }; fetchData();}, [url]);复制代码
const useDataApi = (initialUrl, initialData) => { const [url, setUrl] = useState(initialUrl); const [state, dispatch] = useReducer(dataFetchReducer, { isLoading: false, isError: false, data: initialData, });... return [state, setUrl];};复制代码
const dataFetchReducer = (state, action) => { switch (action.type) { case 'FETCH_INIT': return { ...state, isLoading: true, isError: false }; case 'FETCH_SUCCESS': return { ...state, isLoading: false, isError: false, data: action.payload, }; case 'FETCH_FAILURE': return { ...state, isLoading: false, isError: true, }; default: throw new Error(); }};复制代码
const useDataApi = (initialUrl, initialData) => { const [url, setUrl] = useState(initialUrl); const [state, dispatch] = useReducer(dataFetchReducer, { isLoading: false, isError: false, data: initialData, }); useEffect(() => { let didCancel = false; const fetchData = async () => { dispatch({ type: 'FETCH_INIT' }); try { const result = await axios(url); if (!didCancel) { dispatch({ type: 'FETCH_SUCCESS', payload: result.data }); } } catch (error) { if (!didCancel) { dispatch({ type: 'FETCH_FAILURE' }); } } }; fetchData(); return () => { didCancel = true; }; }, [url]); return [state, setUrl];};复制代码
这是去年八月那会的笔记 今天总结到掘金,自己返回来再看看基础的知识 这里面的hook-api都是大佬封装的 源码打开仔细去看我发现为啥人家就能年入百几万,我们就这么low。
最后对自己说一句:学习渠道和学习方式很重要。 如果有什么好的学习渠道和方式求大家评论下方推荐给我,我们相互学习一波。
作者:Liter 链接:https://juejin.im/post/5e4a5557e51d4526d326b0a3 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。