1. axios全局默认配置和拦截器
项目里太多重复代码了,比如某个action:
//删除商品
export const deleteProduct = (id) => async (dispatch, getState) => {
try {
dispatch({ type: PRODUCT_DELETE_REQUEST })
const { userLogin: { userInfo } } = getState();
const config = {
headers: {
Authorization: `Bearer ${userInfo.token}`
}
}
await axios.delete(`/api/products/${id}`, config)
dispatch({ type: PRODUCT_DELETE_SUCCESS })
alert('商品已被删除!')
} catch (error) {
dispatch({
type: PRODUCT_DELETE_FAIL,
payload: error.response && error.response.data.message ? error.response.data.message : error.message
})
}
}
//创建商品
export const createProduct = () => async (dispatch, getState) => {
try {
dispatch({ type: PRODUCT_CREATE_REQUEST })
const { userLogin: { userInfo } } = getState()
const config = {
headers: {
Authorization: `Bearer ${userInfo.token}`,
}
}
const { data } = await axios.post(`/api/products`, {}, config)
dispatch({ type: PRODUCT_CREATE_SUCCESS, payload: data })
} catch (error) {
dispatch({
type: PRODUCT_CREATE_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message,
});
}
}
像配置config来传token还有下面的error代码等,都是重复的,因此考虑进行优化。
frontend目录中创建一个utils文件夹,并在里面创建一个setupAxios.js文件
然后在index.js中引入
import store from './store';
import setupAxios from './utils/setupAxios';
setupAxios(store);
然后我们来看setupAxios这个文件,具体含义看注释:
toast只是一个捕获并显示错误的弹窗,不展开描述。
import axios from "axios";
import toast from "./toast";
function setupAxios(store) {
// ?.表示如果有token 则取出
const token = store.getState().userLogin.userInfo?.token;
// axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
// 拦截请求
axios.interceptors.request.use(function (config) {
// 存在token则默认配置到请求头中
if (token) {
config.headers['Authorization'] = 'Bearer ' + token
}
return config;
}, function (error) {
return Promise.reject(error);
});
//拦截回应 将action中的错误处理抽离到这里
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
const message = error.response && error.response.data.message
? error.response.data.message
: error.message
if (message) {
toast.error(message);
}
return Promise.reject(message);
});
// 默认配置config
axios.defaults.headers.post['Content-Type'] = 'application/json';
axios.defaults.headers.put['Content-Type'] = 'application/json';
axios.defaults.headers.patch['Content-Type'] = 'application/json';
}
export default setupAxios;
配置完这个文件后我们回到action,修改一下刚刚的createProduct试试,可以对比上面的createProduct看:
//创建商品
export const createProduct = () => async (dispatch) => {
try {
dispatch({ type: PRODUCT_CREATE_REQUEST })
const { data } = await axios.post(`/api/products`, {})
dispatch({ type: PRODUCT_CREATE_SUCCESS, payload: data })
} catch (error) {
dispatch({
type: PRODUCT_CREATE_FAIL,
payload: error
});
}
}
可以看出来首先不用通过getState()从state中解构出userInfo来在config头信息中传递token了,其次也可以使得底下的错误处理代码中的payload十分简洁,实现了代码的优化。
2. 路由懒加载
运用到的技术是是另一篇博客中提到的React.lazy(),来看看是怎么具体应用到项目中的:
首先自己封装好一个LazyLoad方法,根据传入的路径包装组件:
const LazyLoad = (path) => {
const Comp = React.lazy(() => import(`./screens/${path}`))
return (
<React.Suspense fallback={<>加载中...</>}>
{<Comp />}
</React.Suspense>
)
}
然后在路由配置中进行修改:
这个项目用的还是React-Router5,因此注意这里要通过render的方式表示组件。
<Route path="/login" render = {() =>{
return LazyLoad('LoginScreen')
}} />
这样就实现了这个组件的懒加载,至于要用到的参数通过useLocation,useHistory等等Hooks解决即可: