day01

1. 项目开发准备

  1. 1). 描述项目
  2. 2). 技术选型
  3. 3). API接口/接口文档/测试接口

2. 启动项目开发

  1. 1). 使用react脚手架创建项目
  2. 2). 开发环境运行: npm start
  3. 3). 生产环境打包运行: npm run build serve build

3. git管理项目

  1. 1). 创建远程仓库
  2. 2). 创建本地仓库
  3. a. 配置.gitignore
  4. b. git init
  5. c. git add .
  6. d. git commit -m "init"
  7. 3). 将本地仓库推送到远程仓库
  8. git remote add origin url
  9. git push origin master
  10. 4). 在本地创建dev分支, 并推送到远程
  11. git checkout -b dev
  12. git push origin dev
  13. 5). 如果本地有修改
  14. git add .
  15. git commit -m "xxx"
  16. git push origin dev
  17. 6). 新的同事: 克隆仓库
  18. git clone url
  19. git checkout -b dev origin/dev
  20. git pull origin dev
  21. 7). 如果远程修改
  22. git pull origin dev

4. 创建项目的基本结构

  1. api: ajax请求的模块
  2. components: 非路由组件
  3. pages: 路由组件
  4. App.js: 应用的根组件
  5. index.js: 入口js

5 引入antd

  1. 下载antd的包
  2. 按需打包: 只打包import引入组件的js/css
  3. 下载工具包
  4. config-overrides.js
  5. package.json
  6. 自定义主题
  7. 下载工具包
  8. config-overrides.js
  9. 使用antd的组件
  10. 根据antd的文档编写

6. 引入路由

  1. 下载包: react-router-dom
  2. 拆分应用路由:
  3. Login: 登陆
  4. Admin: 后台管理界面
  5. 注册路由:
  6. <BrowserRouter>
  7. <Switch>
  8. <Route path='' component={}/>

7. Login的静态组件

  1. 1). 自定义了一部分样式布局
  2. 2). 使用antd的组件实现登陆表单界面
  3. Form / Form.Item
  4. Input
  5. Icon
  6. Button

8. 收集表单数据和表单的前台验证

  1. 1). form对象
  2. 如何让包含<Form>的组件得到form对象? WrapLoginForm = Form.create()(LoginForm)
  3. WrapLoginFormLoginForm的父组件, 它给LoginForm传入form属性
  4. 用到了高阶函数和高阶组件的技术
  5. 2). 操作表单数据
  6. form.getFieldDecorator('标识名称', {initialValue: 初始值, rules: []})(<Input/>)包装表单项组件标签
  7. form.getFieldsValue(): 得到包含所有输入数据的对象
  8. form.getFieldValue(id): 根据标识得到对应字段输入的数据
  9. 3). 前台表单验证
  10. a. 声明式实时表单验证:
  11. form.getFieldDecorator('标识名称', {rules: [{min: 4, message: '错误提示信息'}]})(<Input/>)
  12. b. 自定义表单验证
  13. form.getFieldDecorator('标识名称', {rules: [{validator: this.validatePwd}]})(<Input/>)
  14. validatePwd = (rule, value, callback) => {
  15. if(有问题) callback('错误提示信息') else callack()
  16. }
  17. c. 点击提示时统一验证
  18. form.validateFields((error, values) => {
  19. if(!error) {通过了验证, 发送ajax请求}
  20. })

9. 高阶函数与高阶组件

  1. 1. 高阶函数
  2. 1). 一类特别的函数
  3. a. 接受函数类型的参数
  4. b. 返回值是函数
  5. 2). 常见
  6. a. 定时器: setTimeout()/setInterval()
  7. b. Promise: Promise(() => {}) then(value => {}, reason => {})
  8. c. 数组遍历相关的方法: forEach()/filter()/map()/reduce()/find()/findIndex()
  9. d. 函数对象的bind()
  10. e. Form.create()() / getFieldDecorator()()
  11. 3). 高阶函数更新动态, 更加具有扩展性
  12. 2. 高阶组件
  13. 1). 本质就是一个函数
  14. 2). 接收一个组件(被包装组件), 返回一个新的组件(包装组件), 包装组件会向被包装组件传入特定属性
  15. 3). 作用: 扩展组件的功能
  16. 3. 高阶组件与高阶函数的关系
  17. 高阶组件是特别的高阶函数
  18. 接收一个组件函数, 返回是一个新的组件函数

day02

1. 后台应用

  1. 启动后台应用: mongodb服务必须启动
  2. 使用postman测试接口(根据接口文档):
  3. 访问测试: post请求的参数在body中设置
  4. 保存测试接口
  5. 导出/导入所有测试接口

2. 编写ajax代码

  1. 1). ajax请求函数模块: api/ajax.js
  2. 封装axios + Promise
  3. 函数的返回值是promise对象 ===> 后面用上async/await
  4. 自己创建Promise
  5. 1. 内部统一处理请求异常: 外部的调用都不用使用try..catch来处理请求异常
  6. 2. 异步返回是响应数据(而不是响应对象): 外部的调用异步得到的就直接是数据了(response --> response.data)
  7. 2). 接口请求函数模块: api/index.js
  8. 根据接口文档编写(一定要具备这个能力)
  9. 接口请求函数: 使用ajax(), 返回值promise对象
  10. 3). 解决ajax跨域请求问题(开发时)
  11. 办法: 配置代理 ==> 只能解决开发环境
  12. 编码: package.json: proxy: "http://localhost:5000"
  13. 4). 对代理的理解
  14. 1). 是什么?
  15. 具有特定功能的程序
  16. 2). 运行在哪?
  17. 前台应用端
  18. 只能在开发时使用
  19. 3). 作用?
  20. 解决开发时的ajax请求跨域问题
  21. a. 监视并拦截请求(3000)
  22. b. 转发请求(4000)
  23. 4). 配置代理
  24. 告诉代理服务器一些信息: 比如转发的目标地址
  25. 开发环境: 前端工程师
  26. 生产环境: 后端工程师
  27. 5). asyncawait
  28. a. 作用?
  29. 简化promise对象的使用: 不用再使用then()来指定成功/失败的回调函数
  30. 以同步编码(没有回调函数了)方式实现异步流程
  31. b. 哪里写await?
  32. 在返回promise的表达式左侧写await: 不想要promise, 想要promise异步执行的成功的value数据
  33. c. 哪里写async?
  34. await所在函数(最近的)定义的左侧写async

3. 实现登陆(包含自动登陆)

  1. login.jsx
  2. 1). 调用登陆的接口请求
  3. 2). 如果失败, 显示错误提示信息
  4. 3). 如果成功了:
  5. 保存userlocal/内存中
  6. 跳转到admin
  7. 4). 如果内存中的user有值, 自动跳转到admin
  8. src/index.js
  9. 读取localuser到内存中保存
  10. admin.jsx
  11. 判断如果内存中没有user(_id没有值), 自动跳转到login
  12. storageUtils.js
  13. 包含使用localStorage来保存user相关操作的工具模块
  14. 使用第三库store
  15. 简化编码
  16. 兼容不同的浏览器
  17. memoryUtils.js
  18. 用来在内存中保存数据(user)的工具类

4. 搭建admin的整体界面结构

  1. 1). 整体布局使用antdLayout组件
  2. 2). 拆分组件
  3. LeftNav: 左侧导航
  4. Header: 右侧头部
  5. 3). 子路由
  6. 定义路由组件
  7. 注册路由

5. LeftNav组件

  1. 1). 使用antd的组件
  2. Menu / Item / SubMenu
  3. 2). 使用react-router
  4. withRouter(): 包装非路由组件, 给其传入history/location/match属性
  5. history: push()/replace()/goBack()
  6. location: pathname属性
  7. match: params属性
  8. 3). componentWillMountcomponentDidMount的比较
  9. componentWillMount: 在第一次render()前调用一次, 为第一次render()准备数据(同步)
  10. componentDidMount: 在第一次render()之后调用一次, 启动异步任务, 后面异步更新状态重新render
  11. 4). 根据动态生成ItemSubMenu的数组
  12. map() + 递归: 多级菜单列表
  13. reduce() + 递归: 多级菜单列表
  14. 5). 2个问题?
  15. 刷新时如何选中对应的菜单项?
  16. selectedKey是当前请求的path
  17. 刷新子菜单路径时, 自动打开子菜单列表?
  18. openKey 一级列表项的某个子菜单项是当前对应的菜单项

day03

1. Header组件

  1. 1). 界面静态布局
  2. 三角形效果
  3. 2). 获取登陆用户的名称显示
  4. MemoryUtils
  5. 3). 当前时间
  6. 循环定时器, 每隔1s更新当前时间状态
  7. 格式化指定时间: dateUtils
  8. 4). 天气预报
  9. 使用jsonp库发jsonp请求百度天气预报接口
  10. jsonp请求的理解
  11. 5). 当前导航项的标题
  12. 得到当前请求的路由path: withRouter()包装非路由组件
  13. 根据pathmenuList中遍历查找对应的itemtitle
  14. 6). 退出登陆
  15. Modal组件显示提示
  16. 清除保存的user
  17. 跳转到login
  18. 7). 抽取通用的类链接按钮组件
  19. 通过...透传所有接收的属性: <Button {...props} /> <LinkButton>xxxx</LinkButton>
  20. 组件标签的所有子节点都会成为组件的children属性

2. jsonp解决ajax跨域的原理

  1. 1). jsonp只能解决GET类型的ajax请求跨域问题
  2. 2). jsonp请求不是ajax请求, 而是一般的get请求
  3. 3). 基本原理
  4. 浏览器端:
  5. 动态生成<script>来请求后台接口(src就是接口的url)
  6. 定义好用于接收响应数据的函数(fn), 并将函数名通过请求参数提交给后台(如: callback=fn)
  7. 服务器端:
  8. 接收到请求处理产生结果数据后, 返回一个函数调用的js代码, 并将结果数据作为实参传入函数调用
  9. 浏览器端:
  10. 收到响应自动执行函数调用的js代码, 也就执行了提前定义好的回调函数, 并得到了需要的结果数据

day04: Category组件

1. 使用antd组件构建分类列表界面

  1. Card
  2. Table
  3. Button
  4. Icon

2. 相关接口请求函数

  1. 获取一级/二级分类列表
  2. 添加分类
  3. 更新分类

3. 异步显示一级分类列表

  1. 设计一级分类列表的状态: categorys
  2. 异步获取一级分类列表: componentDidMount(){}
  3. 更新状态, 显示

4. 显示二级分类列表

  1. 设计状态: subCategorys / parentId / parentName
  2. 显示二级分类列表: 根据parentId状态值, 异步获取分类列表
  3. setState()的问题
  4. setState()更新状态是异步更新的, 直接读取状态值还是旧的状态值
  5. setState({}, [callback]), 回调函数是在状态更新且界面更新之后执行, 可以在此获取最新的状态

5. 更新分类

  1. 1). 界面
  2. antd组件: Modal, Form, Input
  3. 显示/隐藏: showStatus状态为2/0
  4. 2). 功能
  5. 父组(Category)件得到子组件(AddForm)的数据(form)
  6. 调用更新分类的接口
  7. 重新获取分类列表

day05

1. 添加分类

  1. 1). 界面
  2. antd组件: Modal, Form, Select, Input
  3. 显示/隐藏: showStatus状态为1/0
  4. 2). 功能
  5. 父组(Category)件得到子组件(AddForm)的数据(form)
  6. 调用添加分类的接口
  7. 重新获取分类列表

2. Product整体路由

  1. 1). 配置子路由:
  2. ProductHome / ProductDetail / ProductAddUpdate
  3. <Route> / <Switch> / <Redirect>
  4. 2). 匹配路由的逻辑:
  5. 默认: 逐层匹配 <Route path='/product' component={ProductHome}/>
  6. exact属性: 完全匹配

3. 分页实现技术(2种)

  1. 1). 前台分页
  2. 请求获取数据: 一次获取所有数据, 翻页时不需要再发请求
  3. 请求接口:
  4. 不需要指定请求参数: 页码(pageNum)和每页数量(pageSize)
  5. 响应数据: 所有数据的数组
  6. 2). 基于后台的分页
  7. 请求获取数据: 每次只获取当前页的数据, 翻页时要发请求
  8. 请求接口:
  9. 需要指定请求参数: 页码(pageNum)和每页数量(pageSize)
  10. 响应数据: 当前页数据的数组 + 总记录数(total)
  11. 3). 如何选择?
  12. 基本根据数据多少来选择

4. ProductHome组件

  1. 1). 分页显示
  2. 界面: <Card> / <Table> / Select / Icon / Input / Button
  3. 状态: products / total
  4. 接口请求函数需要的数据: pageNum, pageSize
  5. 异步获取第一页数据显示
  6. 调用分页的接口请求函数, 获取到当前页的products和总记录数total
  7. 更新状态: products / total
  8. 翻页:
  9. 绑定翻页的监听, 监听回调需要得到pageNum
  10. 异步获取指定页码的数据显示
  11. 2). 搜索分页
  12. 接口请求函数需要的数据:
  13. pageSize: 每页的条目数
  14. pageNum: 当前请求第几页 (从1开始)
  15. productDesc / productName: searchName 根据商品描述/名称搜索
  16. 状态: searchType / searchName / 在用户操作时实时收集数据
  17. 异步搜索显示分页列表
  18. 如果searchName有值, 调用搜索的接口请求函数获取数据并更新状态
  19. 3). 更新商品的状态
  20. 初始显示: 根据productstatus属性来显示 status = 1/2
  21. 点击切换:
  22. 绑定点击监听
  23. 异步请求更新状态
  24. 4). 进入详情界面
  25. history.push('/product/detail', {product})
  26. 5). 进入添加界面
  27. history.push('/product/addupdate')

5. ProductDetail组件

  1. 1). 读取商品数据: this.props.location.state.product
  2. 2). 显示商品信息: <Card> / List
  3. 3). 异步显示商品所属分类的名称
  4. pCategoryId==0 : 异步获取categoryId的分类名称
  5. pCategoryId!=0: 异步获取 pCategoryId/categoryId的分类名称
  6. 4). Promise.all([promise1, promise2])
  7. 返回值是promise
  8. 异步得到的是所有promsie的结果的数组
  9. 特点: 一次发多个请求, 只有当所有请求都成功, 才成功, 并得到成功的数据,一旦有一个失败, 整个都失败

day06

1. ProductAddUpdate

  1. 1). 基本界面
  2. Card / Form / Input / TextArea / Button
  3. FormItemlabel标题和layout
  4. 2). 分类的级联列表
  5. Cascader的基本使用
  6. 异步获取一级分类列表, 生成一级分类options
  7. 如果当前是更新二级分类的商品, 异步获取对应的二级分类列表, 生成二级分类options, 并添加为对应optionchildren
  8. async函数返回值是一个新promise对象, promise的结果和值由async函数的结果决定
  9. 当选择某个一级分类项时, 异步获取对应的二级分类列表, 生成二级分类options, 并添加为当前optionchildren
  10. 3). 表单数据收集与表单验证

2. PicturesWall

  1. 1). antd组件
  2. Upload / Modal / Icon
  3. 根据示例DEMO改造编写
  4. 2). 上传图片
  5. 在<Upload>上配置接口的path和请求参数名
  6. 监视文件状态的改变: 上传中 / 上传完成/ 删除
  7. 在上传成功时, 保存好相关信息: name / url
  8. 为父组件提供获取已上传图片文件名数组的方法
  9. 3). 删除图片
  10. 当文件状态变为删除时, 调用删除图片的接口删除上传到后台的图片
  11. 4). 父组件调用子组件对象的方法: 使用ref技术
  12. 1. 创建ref容器: thi.pw = React.createRef()
  13. 2. ref容器交给需要获取的标签元素: <PicturesWall ref={this.pw} /> // 自动将将标签对象添加为pw对象的current属性
  14. 3. 通过ref容器读取标签元素: this.pw.current

day07

1. RichTextEditor

  1. 1). 使用基于react的富文本编程器插件库: react-draft-wysiwyg
  2. 2). 参考库的DEMOAPI文档编写
  3. 3). 如果还有不确定的, 百度搜索, 指定相对准确的关键字

2. 完成商品添加与修改功能

  1. 1). 收集输入数据
  2. 通过form收集: name/desc/price/pCategoryId/categoryId
  3. 通过ref收集: imgs/detail
  4. 如果是更新收集: _id
  5. 将收集数据封装成product对象
  6. 2). 更新商品
  7. 定义添加和更新的接口请求函数
  8. 调用接口请求函数, 如果成功并返回商品列表界面

3. 角色管理

  1. 1). 角色前台分页显示
  2. 2). 添加角色
  3. 3). 给指定角色授权
  4. 界面: Tree
  5. 状态: checkedKeys, 根据传入的rolemenus进行初始化
  6. 勾选某个Node时, 更新checkedKeys
  7. 点击OK时: 通过ref读取到子组件中的checkedKeys作为要更新product新的menus
  8. 发请求更新product
  9. 解决默认勾选不正常的bug: 利用组件的componentWillReceiveProps()

day08

1. setState()的使用

  1. 1). setState(updater, [callback]),
  2. updater为返回stateChange对象的函数: (state, props) => stateChange
  3. 接收的stateprops被保证为最新的
  4. 2). setState(stateChange, [callback])
  5. stateChange为对象,
  6. callback是可选的回调函数, 在状态更新且界面更新后才执行
  7. 3). 总结:
  8. 对象方式是函数方式的简写方式
  9. 如果新状态不依赖于原状态 ===> 使用对象方式
  10. 如果新状态依赖于原状态 ===> 使用函数方式
  11. 如果需要在setState()后获取最新的状态数据, 在第二个callback函数中读取

2. setState()的异步与同步

  1. 1). setState()更新状态是异步还是同步的?
  2. a. 执行setState()的位置?
  3. react控制的回调函数中: 生命周期勾子 / react事件监听回调
  4. react控制的异步回调函数中: 定时器回调 / 原生事件监听回调 / promise回调 /...
  5. b. 异步 OR 同步?
  6. react相关回调中: 异步
  7. 其它异步回调中: 同步
  8. 2). 关于异步的setState()
  9. a. 多次调用, 如何处理?
  10. setState({}): 合并更新一次状态, 只调用一次render()更新界面 ---状态更新和界面更新都合并了
  11. setState(fn): 更新多次状态, 但只调用一次render()更新界面 ---状态更新没有合并, 但界面更新合并了
  12. b. 如何得到异步更新后的状态数据?
  13. setState()的callback回调函数中

3. Component与PureComponent

  1. 1). Component存在的问题?
  2. a. 父组件重新render(), 当前组件也会重新执行render(), 即使没有任何变化
  3. b. 当前组件setState(), 重新执行render(), 即使state没有任何变化
  4. 2). 解决Component存在的问题
  5. a. 原因: 组件的shouldcomponentUpdate()默认返回true, 即使数据没有变化render()都会重新执行
  6. b. 办法1: 重写shouldComponentUpdate(), 判断如果数据有变化返回true, 否则返回false
  7. c. 办法2: 使用PureComponent代替Component
  8. d. 说明: 一般都使用PureComponent来优化组件性能
  9. 3). PureComponent的基本原理
  10. a. 重写实现shouldComponentUpdate()
  11. b. 对组件的新/旧stateprops中的数据进行浅比较, 如果都没有变化, 返回false, 否则返回true
  12. c. 一旦componentShouldUpdate()返回false不再执行用于更新的render()
  13. 4). 面试题:
  14. 组件的哪个生命周期勾子能实现组件优化?
  15. PureComponent的原理?
  16. 区别ComponentPureComponent?

4. 用户管理

  1. 1). 显示用户分页列表
  2. 2). 添加用户
  3. 3). 修改用户
  4. 4). 删除用户

5. 导航菜单权限控制

  1. 1). 基本思路(依赖于后台):
  2. 角色: 包含所拥有权限的所有菜单项key的数组: menus=[key1, key2, key3]
  3. 用户: 包含所属角色的ID: role_id
  4. 当前登陆用户: user中已经包含了所属role对象
  5. 遍历显示菜单项时: 判断只有当有对应的权限才显示
  6. 2). 判断是否有权限的条件?
  7. a. 如果当前用户是admin
  8. b. 如果当前item是公开的
  9. c. 当前用户有此item的权限: key有没有menus
  10. d. 如果当前用户有此item的某个子item的权限

day09

1. redux理解

  1. 什么?: redux是专门做状态管理的独立第3方库, 不是react插件, 但一般都用在react项目中
  2. 作用?: 对应用中状态进行集中式的管理(写/读)
  3. 开发: react-redux, redux-thunk等插件配合使用

2. redux相关API

  1. redux中包含: createStore(), applyMiddleware(), combineReducers()
  2. store对象: getState(), dispatch(), subscribe()
  3. react-redux:
  4. <Provider store={store}>: 向所有的容器组件提供store
  5. connect(
  6. state => ({xxx: state.xxx}),
  7. {actionCreator1, actionCreator2}
  8. )(UI组件):
  9. 产生的就是容器组件, 负责向UI组件传递标签属性,
  10. 一般属性值从state中获取, 函数属性内部会执行dispatch分发action

3. redux核心概念(3个)

  1. action:
  2. 默认是对象(同步action), {type: 'xxx', data: value}, 需要通过对应的actionCreator产生,
  3. 它的值也可以是函数(异步action), 需要引入redux-thunk才可以
  4. reducer
  5. 根据老的state和指定的action, 返回一个新的state
  6. 不能修改老的state
  7. store
  8. redux最核心的管理对象
  9. 内部管理着: statereducer
  10. 提供方法: getState(), dispatch(action), subscribe(listener)

4. redux工作流程

5. 使用redux及相关库编码

  1. 需要引入的库:
  2. redux
  3. react-redux
  4. redux-thunk
  5. redux-devtools-extension(这个只在开发时需要)
  6. redux文件夹:
  7. action-types.js
  8. actions.js
  9. reducers.js
  10. store.js
  11. 组件分2类:
  12. ui组件(components): 不使用redux相关API
  13. 容器组件(containers): 通过connect()()生成的组件

day10

1. 在项目中搭建redux整套环境

  1. 1). store.js
  2. 2). reducer.js
  3. 3). actions.js
  4. 4). action-types.js
  5. 5). index.js
  6. 6). 在需要与redux进行状态数据通信(读/写)的UI组件包装生成容器组件

2. 通过redux管理头部标题headTitle数据

  1. 1). action-types.js
  2. 2). actoins.js
  3. 3). reducer.js
  4. 4). 相关组件:
  5. left-nav.js
  6. header.js

3. 通过redux管理登陆用户信息user数据

  1. 1). action-types.js
  2. 2). actoin.js
  3. 3). reducer.js
  4. 4). 相关组件:
  5. login.js
  6. admin.js
  7. left-nav.js
  8. header.js
  9. role.js

4. 自定义redux库

  1. 1). redux库向外暴露下面几个函数
  2. createStore(): 接收的参数为reducer函数, 返回为store对象
  3. combineReducers(): 接收包含nreducer方法的对象, 返回一个新的reducer函数
  4. applyMiddleware() // 暂不实现
  5. 2). store对象的内部结构
  6. getState(): 返回值为内部保存的state数据
  7. dispatch(): 参数为action对象
  8. subscribe(): 参数为监听内部state更新的回调函数
  9. 3). combineReducers函数:
  10. 返回的总reducer函数内部会根据总的state和指定的action,
  11. 调用每个reducer函数得到对应的新的state, 并封装成一个新的总state对象返回

5. 自定义react-redux库

  1. 1). react-redux向外暴露了2API
  2. a. Provider组件类
  3. b. connect函数
  4. 2). Provider组件
  5. 接收store属性
  6. 通过contextstore暴露给所有的容器子组件
  7. Provider原样渲染其所有标签子节点
  8. 3). connect函数
  9. 接收2个参数: mapStateToPropsmapDispatchToProps
  10. connect()执行的返回值为一个高阶组件: 包装UI组件, 返回一个新的容器组件
  11. mapStateToProps:
  12. 为一个函数, 返回包含n个一般属性对象,
  13. 容器组件中调用得到对象后, 初始化为容器组件的初始状态, 并指定为UI组件标签的一般属性
  14. mapDispatchToProps:
  15. 如果为函数, 调用得到包含ndispatch方法的对象
  16. 如果为对象, 遍历封装成包含ndispatch方法的对象
  17. 将包含ndispatch方法的对象分别作为函数属性传入UI组件
  18. 通过store绑定state变化的监听, 在回调函数中根据store中最新的state数据更新容器组件状态, 从而更新UI组件

day11

1. 数据可视化

  1. 1). echarts(百度) ==> echarts-for-react
  2. 2). g2(阿里) ==> bizCharts
  3. 3). d3(国外)

2. 前台404界面

  1. <Redirect from='/' to='/home' exact/>
  2. <Route component={NotFound}/>

3. 打包应用运行

  1. 1). 解决生产环境ajax跨域问题
  2. 使用nginx的反向代理解决(一般由后台配置)
  3. CORS: 允许浏览器端跨域
  4. 2). BrowserRouter模式刷新404的问题
  5. a. 问题: 刷新某个路由路径时, 会出现404的错误
  6. b. 原因: 项目根路径后的path路径会被当作后台路由路径, 去请求对应的后台路由, 但没有
  7. c. 解决: 使用自定义中间件去读取返回index页面展现

《React后台管理系统实战 零》:基础笔记的更多相关文章

  1. 《React后台管理系统实战 :一》:目录结构、引入antd、引入路由、写login页面、使用antd的form登录组件、form前台验证、高阶函数/组件

    实战 上接,笔记:https://blog.csdn.net/u010132177/article/details/104150177 https://gitee.com/pasaulis/react ...

  2. 《React后台管理系统实战 :三》header组件:页面排版、天气请求接口及页面调用、时间格式化及使用定时器、退出函数

    一.布局及排版 1.布局src/pages/admin/header/index.jsx import React,{Component} from 'react' import './header. ...

  3. 《React后台管理系统实战 :二》antd左导航:cmd批量创建子/目录、用antd进行页面布局、分离左导航为单独组件、子路由、动态写左导航、css样式相对陷阱

    一.admin页面布局及路由创建 0)cmd批量创建目录及子目录 //创建各个目录,及charts和子目录bar md home category product role user charts\b ...

  4. 《React后台管理系统实战 :四》产品分类管理页:添加产品分类、修改(更新)产品分类

    一.静态页面 目录结构 F:\Test\react-demo\admin-client\src\pages\admin\category add-cate-form.jsx index.jsx ind ...

  5. 知了课堂 Python Flask零基础 笔记整理

    目录 起步 安装Python2.7: Python虚拟环境介绍与安装: pip安装flask: 认识url: URL详解 web服务器和应用服务器以及web应用框架: Flask 第一个flask程序 ...

  6. 【共享单车】—— React后台管理系统开发手记:主页面架构设计

    前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. ...

  7. react后台管理系统路由方案及react-router原理解析

        最近做了一个后台管理系统主体框架是基于React进行开发的,因此系统的路由管理,选用了react-router(4.3.1)插件进行路由页面的管理配置. 实现原理剖析 1.hash的方式   ...

  8. Serverless + Egg.js 后台管理系统实战

    本文将介绍如何基于 Egg.js 和 Serverless 实现一个后台管理系统 作为一名前端开发者,在选择 Nodejs 后端服务框架时,第一时间会想到 Egg.js,不得不说 Egg.js 是一个 ...

  9. 【共享单车】—— React后台管理系统开发手记:AntD Table基础表格

    前言:以下内容基于React全家桶+AntD实战课程的学习实践过程记录.最终成果github地址:https://github.com/66Web/react-antd-manager,欢迎star. ...

随机推荐

  1. 【译】高级T-SQL进阶系列 (三)【中篇】:理解公共表表达式(CTEs)

    [译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正] 原文链接:传送门. 一个简单的CTE例子 如前所述,CTE‘s提供给你了一个方法来更容易的书写复杂的代码以提高其可读性.假设你有列表 ...

  2. P1579

    AC: #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for(int i = a; i < b ...

  3. 总结 jion,group join 基于方法的查询与查询表达式 对比

    数据源: 代码: using (tempdbEntities context = new tempdbEntities()) { #region 基于方法的查询 Console.WriteLine(& ...

  4. SQLite3介绍

    一.SQLite数据库简介 SQLite 是一个软件库,实现了自给自足的.无服务器的.零配置的.事务性的 SQL 数据库引擎.SQLite 是在世界上最广泛部署的 SQL 数据库引擎. DDL - 数 ...

  5. JDK8源码解析 -- HashMap(二)

    在上一篇JDK8源码解析 -- HashMap(一)的博客中关于HashMap的重要知识点已经讲了差不多了,还有一些内容我会在今天这篇博客中说说,同时我也会把一些我不懂的问题抛出来,希望看到我这篇博客 ...

  6. GIT 协同开发

    Git 是一个开源的分布式版本控制系统,用于敏捷高效的处理任何项目的版本问题.Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件.与cvs, ...

  7. 如何查看Ubuntu系统版本

    在Ubuntu终端,常用以下几种方式查看系统版本: 一.uname -a 二.cat /etc/issue 三.cat /etc/lsb-release 四.lsb_release -a 五.cat ...

  8. 【代码总结】GD库中简单的验证码

    大体思路: 代码部分: <?php //1.创建画布 $img = imagecreatetruecolor(100,30); //2.设置颜色 值越小,颜色越深 $color1 = image ...

  9. linux与python3安装redis

    1.linux安装redis服务 apt-get install redis* 进入客户端管理 redis-cli 启动服务 service redis startservice redis rest ...

  10. mybatis源码探索笔记-5(拦截器)

    前言 mybatis中拦截器主要用来拦截我们在发起数据库请求中的关键步骤.其原理也是基于代理模式,自定义拦截器时要实现Interceptor接口,并且要对实现类进行标注,声明是对哪种组件的指定方法进行 ...