项目第一步 确认业务
旅游电商电商四套主线业务:展示旅游路线,网站登录,购物车结果,下单购买
二级业务:主页推荐,关键词搜索,登陆注册,购物车操作,订单历史记录
所以可以分成四个模块,产品模块,用户模块,购物模块,订单模块
产品模块:主页推荐,关键词搜索, 展示旅游路线
用户模块: 登陆注册
购物模块: 购物车操作
订单模块: 订单历史记录
流程规划
安装ts的css模块化
cnpm isntall typescript-plugin-css-modules --save
组件库使用antd,
考虑一个问题,antd是否会将没有用的代码引入,造成包很大?
答案是不会的,antd官网有提示,antd的js代码是支持基于ES module 的 tree shaking,对于js部分,直接引入import {} form './.xx/,就会有按需加载的效果
什么是tree shaking,摇晃树,最直接的就是果子成熟了,要不断摇晃下来,对树没有帮助了。比如我定义一个函数,却不曾调用过。所以我们就要把这个函数去掉不打包。tree shaking就是做这种事情。对没有用的代码摇下去。
craco
安装craco,这个可以在不暴露webpack的情况下增加额外的配置信息。而且在我们引入antd的时候,antd的主题是蓝色的,但我们不想要蓝色的,也可以通过craco来配置
yarn add @craco/craco
然后修改配置文件,我们要以craco来启动项目
现在是以craco启动。craco启动的时候会多做一件事情,就是读取根目录下的craco.config.js文件去合并配置文件。
配置antd主题
按他要求安装craco-less
再次yarn start启动
就会发现已经改了。
配置别名
在里面对webpack进行配置,alias是配置别名的意思。然后我们是ts项目,所以要
这样你在ts文件里才能使用@。
编译成功。
别名配置结束
我们还可以在这个文件配置其他更多的东西。具体看需要引入。
配置i18n
npm install react-i18next i18next --save
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import zh_hans from './zhans';
import zh_hant from './zhant';
import en from './en';
let lang = localStorage.getItem('language');
if (!lang) {
lang = 'zh_hans';
localStorage.setItem('language', 'zh_hans');
}
i18n
.use(initReactI18next) // passes i18n down to react-i18next
.init({
resources: {
en: {
translation: en
},
zh_hans: {
translation: zh_hans
},
zh_hant: {
translation: zh_hant
}
},
fallbackLng: lang,
debug: false,
interpolation: {
escapeValue: false
},
cleanCode: true,
lowerCaseLng: true
});
export default i18n;
export const t = ( num: string, desc?: any ) => {
return i18n.t(num, desc)
}
然后在每个文件导出
在主文件引入
使用的时候
可以看到配置成功了。语言切换,在reudx配置
只要调用了i18n.changeLanguage就可以修改语言。
如
但这个只要一刷新就会没有。所以可以使用保存在本地存储的方式
自定义一个hooks
当改变类型就传入LocalStorage,然后调用history
强制刷新一下,这样就能保证以后刷新都能通过本地存储的数据去获取语言类型。
认识RESTful
REST(表征性状态转移)
restful基本特点:无状态,面向资源 ,使用http的动词
无状态:一次连接,返回结果。不存在依赖于上次调用的情况,像webStocket不属于restful范畴
面向资源:在url种,只会出现名词,不会出现动词。面向资源,HATOAS超媒体即应用状态引擎
使用http的动词。如 get post put delete patch(部分更新) 对资源的操作
相同的url可以根据不同的http请求做对应的操作
那restful api好用不,面向对象,资源,如增删改查很方便。面向过程,如登录,不太好用。
px适配自定义Hooks
import { useLifecycles } from 'react-use';
interface IPx2RemProps {
pWidth: number; //草稿宽度
cWidth: number; //屏幕实际宽度
pRem: number; //转换倍数
}
//定义一个类,实现改写html的字体大小功能
class Px2Rem implements IPx2RemProps {
pWidth: number = 1285;
cWidth: number = 1285;
pRem: number = 100;
constructor(pWidth: number, pRem: number) {
this.pWidth = pWidth;
this.pRem = pRem;
}
setRem = (): void => {
const html = document.documentElement;
let realCwidth = document.body.clientWidth || html.clientWidth; //获取真正的宽度
this.cWidth =
realCwidth > 1285 ? 1285 : realCwidth < 800 ? 800 : realCwidth;
let realFontSize = (this.cWidth / this.pWidth) * this.pRem; //换算 当页面=1280时,1rem = 100px 随着页面缩小, 1rem会越来越小
html.style.fontSize = realFontSize + 'px'; // html的font-size就等于1rem
};
getRemToPx = (rem: number): number => {
return (this.cWidth / this.pWidth) * this.pRem * rem; //返回 x rem的值
};
}
const px2rem = new Px2Rem(1285, 100);
const setRem = () => {
px2rem.setRem();
};
export const useSetRem = () => {
useLifecycles(
() => {
//相当于componentDidMount
setRem();
window.addEventListener('resize', setRem);
},
() => {
//相当于 componentWillUnMount
window.removeEventListener('resize', setRem);
}
);
};
然后root组件引入
这样只要我们写的时候引入插件,转换成rem,就可以自动适配了。
引入redux 并且使用immutable优化
cnpm install redux react-redux redux-immutable redux-thunk immutable
cnpm install @types/react-redux @types/redux-immutable -D
创reducer函数
创store,合并reducer
注入store
函数组件中使用react-redux![在这里插入图片描述](https://img-blog.csdnimg.cn/20210409181137511.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpbl9maWdodGlu,size_16,color_FFFFFF,t_70)
后面的shallowEqual是为了优化,因为不加的话,每次redux数据一改变,返回的都是新的对象,所以会导致组件进行不必要的渲染。而shallowEqual是会对前后的state进行一个浅层比较,若值不变则返回的都是老值,不会更新组件。
正常拿到redux的数据了。
actions配合typescript
不同的接口对应不同的事情,然乎导出
可以看到提示什么的都有了,这也就是ts的强大之处。
配置路由react-router
cnpm install react-router-dom @types/react-router-dom
路由配置用react-router-dom第六版
配置成功
路由参数获取
import { useNavigate, useLocation, useParams } from ‘react-router-dom’
useHistory用useNavigate代替了,
用法:
封装axios
配置中间件redux-thunk
这个的原理其实很简单,劫持actions,判断是函数还是对象,对象的话直接dispatch,函数的话则运行并且传入store.dispatch,store.getState()给他。
配置也很简单
使用的时候
可以看到ThunkActions需要传入四个参数,分别是函数的返回值,store的类型,函数参数,Actions的类型。及返回的对象的类型,然后返回一个函数,里面有两个参数,dispatch,state的值。可以在这里面发送网络请求。
中间件概念
中间件公式
为什么是嵌套三层呢?因为react调用中间件就是这么调用的。
接下来我们自定义一个中间件
中间件在我们处理副作用的时候非常好用,
认识redux-toolkit
这是RKT依赖的四个库。最重要是这个immer库,通过它可以直接修改redux中的state。
他的思路就是创建slice,在slice初始化state,然后reducer与action结合在一起了,可以通过赋值的方式直接修改state,表面上看似违背了immer的原则,实则不是,他这个的底层是重新创建了state,然后替代原来的state,只是允许我们使用这种方式来修改state。
看基本使用
使用的时候直接dispatch(languageSlice.actions.checkouLanguage())
redux-toolkit默认内置了redux-thunk,
这种是完全自动流控制数据,中间件会返回一个pormise,在对应的extraReducers上面写上对应的状态,toolkit会在对应的的时刻执行这个函数,如果想要手动控制也行,中间件的函数中的第二个参数thunkApi里面提供了各种api,包括thunkApi.dispatch,允许我们手动dispatch自定义的actions,从而达到控制数据的目的。
使用的时候也是直接dispatch这个中间件,这个粤安action的一种。
这个的确很方便,也减少了代码量,我几乎不用再写action。
解决取出中文url乱码问题,
使用encodeURI(‘我是中文Url’)进行编码,使用decodeURl()进行解码
也可试试直接使用
上面是解码的,下面是没解码。