一. 项目概览

- 上面的今日头条项目,源码在课件资料中寻找



二. 项目介绍
- 爱彼迎项目:
- 爱彼迎团队:
- 开发团队国内200多个人
- 经历过数年版本迭代最终完成的一个产品
- 爱彼迎目前的项目
- 已经不针对国内房东、订房进行维护,依然可以订阅国外的房屋
- 爱彼迎已经退出中国市场,不排除有一天国内的网站不能继续访问
- 项目本身确实非常美观、好看
- 爱彼迎团队:
- 项目核心学习、掌握的知识点:
- 对于第一个
React
项目,我们的核心是对前面所学知识进行练习、实战 - 掌握
React
开发的流程、模式、项目架构,项目中会有很多组件、工具等封装、抽取、复用思想 - 最重要的是学习
React
开发的模式和编程的思想,而不是局限于我上课期间所讲的内容,并且大部分样式和布局内容需要大家课下自行完成 - 在这个项目过程中,我会尽量将之前所学的所有知识都运用起来,但是我们不会为了用某个知识而用某个知识
- 课程中会使用我服务器已经获取到的数据,一是国内的数据更好看,二是担心它数据有一天不再维护,三是我对数据已经进行了大量的整理
- 后续我们还会专门学习
React+TypeScript
项目实战的内容,React
本身非常的灵活,对js
本身要求也较高,但是最重要的还是练习
- 对于第一个
三. 项目规范
- 项目规范:项目中有一些开发规范和代码风格
- 文件夹、文件名称统一小写、多个单词以连接符(
-
)连接 JS
变量名称采用小驼峰标识,常量全部使用大写字母,组件采用大驼峰CSS
采用普通CSS
和styled-component
结合来编写(全局采用普通CSS
、局部采用styled-component
)- 整个项目不再使用
class
组件,统一使用函数式组件,并且全面拥抱Hooks
- 所有的函数式组件,为了避免不必要的渲染,全部使用
memo
进行包裹 - 组件内部的状态,使用
useState、useReducer
;业务数据全部放在redux
中管理 - 函数组件内部基本按照如下顺序编写代码:
- 组件内部
state
管理 redux
的hooks
代码- 其他
hooks
相关代码(比如自定义hooks
) - 其他逻辑代码(网络请求/事件监听/副作用)
- 返回
JSX
代码
- 组件内部
redux
代码规范如下:redux
目前我们学习了两种模式,一种普通方式,一种RTK
,在项目实战中尽量两个都用起来,都需要掌握- 每个模块有自己独立的
reducer
或者slice
,之后合并在一起 redux
中会存在共享的状态、从服务器获取到的数据状态
- 网络请求采用
axios
- 对
axios
进行二次封装 - 所有的模块请求会放到一个请求文件中单独管理
- 对
- 项目使用
AntDesign、MUI(Material UI)
- 爱彼迎本身的设计风格更多偏向于
Material UI
,但是课程中也会尽量讲到AntDesign
的使用方法 - 项目中某些
AntDesign、MUI
中的组件会被拿过来使用 - 但是多部分组件还是自己进行编写、封装、实现
- 爱彼迎本身的设计风格更多偏向于
- 其他规范在项目中根据实际情况决定和编写
- 文件夹、文件名称统一小写、多个单词以连接符(
四. 创建React项目
创建项目的方式:
create-react-app
项目配置:
- 配置项目的
icon
- 配置项目的标题
- 配置
jsconfig.json
- 增强
vscode
的智能提示 react
项目中不能在该文件中写注释- 会报如下错误
Unexpected token / in JSON at position xxx(编译后的行号)
- 意思就是:意外的符号
/
在JSON
位置xxx
号
- 增强
- 配置项目的
通过
craco
配置别名和less
文件:jsconfig.json
中配置的别名,只是为了增强vscode
的智能提示- 所以必须通过
webpack
来配置alias
别名,当然react
中默认是隐藏了webpack
的配置文件的,我们这里采用的是craco
来修改webpack
配置文件,当然还有一种方式是通过npm run eject
命令来暴露webpack
配置文件(不介意使用)
js// craco.config.js const path = require('path') const resolve = pathname => path.resolve(__dirname, pathname) const CracoLessPlugin = require('craco-less'); module.exports = { plugins: [ { plugin: CracoLessPlugin, // 下面这些是针对ant design增加的一些配置,如果没用到ant design,可以不配置下面的选项 // options: { // lessLoaderOptions: { // lessOptions: { // modifyVars: { '@primary-color': '#1DA57A' }, // javascriptEnabled: true, // }, // }, // }, }, ], webpack: { "alias": { "@": resolve('src'), "components": resolve('src/components'), "utils": resolve('src/utils') } } };
五. 项目目录结构划分
对项目进行目录结构的划分:
assets
:资源文件夹,像img
,css
等base-ui
:多个项目都可能用到的公共ui
组件components
:公共组件库hooks
:存放自定义hook
router
:路由相关文件services
:网络请求相关文件store
:状态管理相关文件utils
:一些工具文件views
:视图文件
六. CSS
样式的重置
对默认
CSS
样式进行重置:npm
安装一个normalize.css
shellnpm i normalize.css
手动创建一个
reset.css
在
css/index.less
文件中引入下面文件,index.js
入口文件中引入index.less
即可- 引入之后,就会在
webpack
的依赖图中,到时候打包的时候,webpack
就会帮我对引入的文件进行打包
- 引入之后,就会在
默认是无法打包
less
文件的,这里需要安装less
shellnpm i less -D
七. 全家桶 – Router
配置
- 安装
redux router

八. 全家桶 – Redux
状态管理
Redux
状态管理的选择:普通方式:目前项目中依然使用率非常高
@reduxjs/toolkit
方式:推荐方式, 未来的趋势安装
Redux Toolkit
:Redux ToolKit
本质上其实是对编写redux
做的一层封装,如果想在react
中使用,还是需要安装react-redux
包才行redux toolkit
内部有依赖redux
,所以不需要再安装redux
了
jsnpm install @reduxjs/toolkit react-redux
九. 网络请求 - axios

十. 项目细节
首页
header
部分采用display
布局,左右两项采用flex
为1
,中间一项就会居中svg
相当于通过一大堆标签,路径的方式画出来图案,就不是图片了,可以让网站资源更小一些,加快首页的渲染速度怎么引入
svg
呢?方式一:
- 将
svg
保存成一张图片,如xxx.svg
,之后当成图片去引用,如<img src='xxx.svg'/>
、background-image: url('xxx.svg')
- 将
方式二:
使用
svg
标签,直接嵌入到对应的html
标签中,这样做的好处是:svg
的内容会随着html
文件的下载,跟着一块下载下来,这样后续就不需要再去请求对应的图片,且svg
是一个相对比较小的文件我们可以以组件的形式进行嵌套
但是需要注意,在
jsx
中嵌套svg
,还需要对style
中对应的属性转化为js
对象所以我们可以使用一个工具函数来进行转化
js// input: "display: block; font-size: 80px; background-image: url('xxx.jpg')" // output: {display: 'block', fontSize: '80px', backgroundImage: "url('xxx.jpg')"} function styleStrToObject(styleStr) { const obj = {} const s = styleStr.toLowerCase() .replace( /-(.)/g, function (m, g) { return g.toUpperCase(); } ) .replace( /;\s?$/g, "" ) .split( /:|;/g ) for (var i = 0; i < s.length; i += 2) { obj[s[i].replace(/\s/g,"")] = s[i+1].replace(/^\s+|\s+$/g,"") } return obj } export default styleStrToObject
如何修改
svg
的color
,我们可以修改离它最近父元素的color
,因为svg
会使用离它最近的父元素的color
在
React
中,基于webpack
环境,动态引入本地图片方式一:
import
引入对应的图片style.js
文件中组件中
方式二:
require
函数进行包裹,包裹之后意味着是一个js
代码style.js
文件中组件中
早期
react
中,需要使用的是require
函数返回值的default
属性,才能拿到图片这些特性都是
webpack
的,而不是react
的,而vue-loader
有做特殊处理,所以可以在.vue
文件中使用~assets
来获取jsxrequire("xxx/xxx/xxx.jpg").default
Material UI
默认使用的是emotion
作为样式引擎,如果想要使用styled-components
代替,安装命令如下:jsnpm install @mui/material @mui/styled-engine-sc styled-components
https://mui.com/zh/material-ui/getting-started/installation/
然后,我们只需要在
webpack
配置alias如
下:jsmodule.exports = { //... + resolve: { + alias: { + '@mui/styled-engine': '@mui/styled-engine-sc' + }, + }, };
https://mui.com/zh/material-ui/guides/styled-engine/
但是按照上面步骤(来自官网)执行可能会遇到一些问题,导致项目报错,比如组件,然后报错:不能从
undefined
中读取xxx
测试解决办法:可以采取
emotion
的方案,然后注释前面设置的别名配置:'@mui/styled-engine': '@mui/styled-engine-sc'
那如果
css in js
使用styled-components
,然后又安装emotion
,会不会造成打包文件较大呢?- 不会,因为打包出来的文件都是我们项目中应用到的,最终转化为普通的
css
文件
- 不会,因为打包出来的文件都是我们项目中应用到的,最终转化为普通的
无论是
Vuex/pinia
,还是redux
,本质都是通过js
代码存储在内存中的数据,在网页刷新/重定向的时候,都会丢失

如果
Suspense
组件放在Provider
组件外部,在某些异步组件未加载完成时,意味着通过Provider
给store
里的某些东西提供数据的时候,很有可能这个页面js
文件还未加载下来,下载下来之后,在该页面修改store
中的数据,其他页面是不会监听到该页面发出去的事件的这些是源码内部所作的处理,源码的
subcribe
是不会监听异步加载的页面所发出去dispatch
的事件,虽然能修改数据解决办法:
- 将
Suspense
放在Provider
组件内部 - 意味着
Suspense
组件本身就属于Provider
组件的一部分,对于Provider
内部页面所发生的dispatch
的事件,就能监听到
- 将
Suspense
放置到如下位置时,导致AppHeader
组件打印两次问题的解决:将
Suspense
放置到使用useRoutes
函数的组件当中进行包裹,因为Suspense
只需要对异步组件进行包裹,但是如果提供一个字符串,效果并不好,页面上会出现该字符串闪出然后切换,最好是组件或空字符串(用户不易感知)如果多级路由中,子路由也有使用异步加载,可以给父路由中的
Outlet
占位组件也包裹一层Suspense
组件(这样当父路由中的子路由发生变化,最外层useRoutes
所包裹的Suspense
的替代方案将被子路由这一层中的Suspense
所替代,也就不会引起父路由那一层级的也进行闪烁)
CRA + craco + postcss 实现移动端适配
https://4k8k.xyz/article/weixin_51491109/125889716