阅读前提:希望你对react-hook的官方文档有几次阅读。
下面我基本是拿了人家的代码直接过来自己执行。该骂看起来不难,重要的是人家的思路值得学习。 如果想看原味的请移步这里参考地址,仔细看完你会觉得太美了。
下面的代码是封装类似于useHttp的自定义hook。
import React, { useState } from 'react';
function App() {
const [data, setData] = useState({ hits: [] });
return (
{data.hits.map(item => (
-
{item.title}
))}
);
}
export default App;
复制代码
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 (
{data.hits.map(item => (
-
{item.title}
))}
);
}
export default App;
复制代码
可以替代原来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)}
/>
{data.hits.map(item => (
-
{item.title}
))}
);
}
export default App;
复制代码
执行一次
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 ? (
Loading ...
) : (
{data.hits.map(item => (
-
{item.title}
))}
)}
);
}
export default App;
复制代码
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 && Something went wrong ...}
{isLoading ? (
Loading ...
) : (
{data.hits.map(item => (
-
{item.title}
))}
)}
);
}
export default App;
复制代码
{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 (
{
doFetch(`http://hn.algolia.com/api/v1/search?query=${query}`);
event.preventDefault();
}}>
setQuery(event.target.value)}
/>
...
);
}
复制代码
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插件地址 这里面的hook-api都是大佬封装的 源码打开仔细去看我发现为啥人家就能年入百几万,我们就这么low。
最后对自己说一句:学习渠道和学习方式很重要。 如果有什么好的学习渠道和方式求大家评论下方推荐给我,我们相互学习一波。
作者:Liter
链接:https://juejin.im/post/5e4a5557e51d4526d326b0a3
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。