目录
- bug
- 初始化脚手架
- react脚手架
- 创建项目并启动
- 脚手架文件介绍
- 案例:hello react
- 快捷键
- 组件化编码流程
- 脚手架配置代理方法
- 前置说明
- 常用的ajax请求库
- 配置方法一:只能配置一个路径
- 配置方法二:配置多个路径
- 引入bootsrtrap
- 消息订阅与发布(组件间通信)
- 拓展:fetch(关注分离的设计思想)
- SPA应用
- 路由
- 什么是路由?
- 路由分类
- react-router的理解
- react-router-dom相关API
- 路由组件和一般组件
- 案例navlink封装
- switch
- 解决样式丢失问题
- 路由模糊匹配与严格匹配
- redirect(重定向)的使用
- 二级路由
- 路由组件传递params参数
- 向路由组件传递search参数
- 向路由组件传递state参数
- push和replace
- 编程式路由导航
- withRouter
- BrowserRouter与Hash
- antd
- 按需引入
- redux
- redux简介
- redux是什么
- 什么情况下使用redux
- redux原理图
- redux的三个核心概念
- action
- reducer
- store
- 求和案例完整版
- 异步action
- react-redux
- 基本使用
- 求和案例
- react-redux求和案例优化
- 优化1
- 优化2
- 优化3
- 优化总结
- 数据共享
- 纯函数
- redux开发者工具
- setState
- lazy
- hooks
- fragment
- context
- purecomponent
- render props
- 错误边界
- 组件间通信总结
- reactrouter6
bug
由于版本造成的不会影响页面的报错https://juejin.cn/post/7082221953972437022
初始化脚手架
react脚手架
- xxx脚手架:用来帮助程序员快速创建一个基于xxx库的模板项目
1. 包含了所有需要的配置(语法检查‘jsx编译devServer)
2. 下载了所有相关的依赖
3. 可以直接运行一个简单效果 - react提供了一个用于创建react项目的脚手架库create-react-app
- 项目的整体技术架构为:react+webpack+es6+eslit
- 使用脚手架开发的项目的特点:模块化、组件化、工程化
创建项目并启动
- 全局安装:npm install create-react-app -g
- 切换到县创建项目的目录,使用命令:create-react-app hello-react
- 进入项目文件夹:cd hello-react
- 启动项目:npm start
特别注意:如果react-tools工具如果是4以下的版本启动起来会报错,所以要下载4以上的版本,因为react自动会下载最新版本。
脚手架文件介绍
案例:hello react
用于区分组件还是js文件-------组件后缀是jsx是组件--------js文件后缀是js
css如果两个文件样式有冲突则会覆盖(谁在下面引入的css谁就保留),解决办法如下
1.如果用less/scss可以在外面包住id=“hello”.hello{ .title{} }
2.模块css
快捷键
里面有快捷键介绍 例如:rcc-----react的模板快捷键
组件化编码流程
- 拆分组件:拆分界面,抽取组件
- 实现静态化组件:使用组件实现静态化页面效果
- 实现动态组件
- 动态显示初始化数据
1. 数据类型
2. 数据名称
3. 保存在哪个组件 - 交互从绑定事件监听开始
- 动态显示初始化数据
引入包规则:
1.成型的包往上靠
2.自己的包往下靠
3.样式一般放在最后
//注意:
<input type="checkbox" defaultChecked = "true"/>
//defaultChecked 默认值是true后期点击是可以该的---改属性只在第一次起作用
//checked后期是不可以更改的 但是如果加上change就可以更改
//类型限制:需要自己下载 prop-types
//在react函数方法里用window的方法,需要前面加window.方法即可
案例
案例总结知识点
- 拆分组件,实现静态组件,注意:className、style的写法
- 动态初始化列表,如何确定将数据放在哪个组件的state中?
——某个组件使用:放在其自身的dtate中
——某些组件使用:放在他们共同的父组件state中(官方称此操作为:状态提升) - 关于父子之间通信
1. 【父组件】给【子组件】传递数据:通过props传递
2. 【子组件】给【父组件】传递数据:通过props传递,要求父提前给子传递一个函数 - 注意defaultChecked和checked的区别,类似的还有defaultValue和value
- 状态在哪里,操作状态的方法就在哪里
脚手架配置代理方法
前置说明
- react本身只关注于界面,并不包含发送ajax请求的代码
- 前端应用需通过ajax请求与后台进行交互(json数据)
- react应用中需要集成第三方ajax库或自己封装
常用的ajax请求库
-
jquery比较重,如果需要另外引入不建议使用
-
axios轻量级,建议使用
1. 封装XMLHTTPRequest对象的ajax
2. promise风格
3. 可以用在浏览器的node服务器端 -
npm i axios --save
-
import axios from ‘axios’
配置方法一:只能配置一个路径
axios.get('/student').then(
response =>{console.log('成功了',response.data)}
error = >{console.log('失败了',error)}
)
注意:修改pack.json文件需要重新启动才会生效刚刚更改的
- 优点:配置简单,前端请求资源时可以不加任何前缀
- 缺点:不能配置多个代理
- 工作方式:该配置代理,相当于请求了3000不存在的资源时,name该请求转发给5000(优享匹配前端资源)
配置方法二:配置多个路径
- 在src中创建setupProxy.js(名字固定)
- 该文件里面不能用es6的写法要用common.js
//setupProxy.js
const proxy = require('http-proxy-middleware')
module.exports = function(app){
app.use(
proxy('/api',{//遇见/api的前缀的请求,就会触发该代理配置
target:'http://localhost:5000',//请求转发给谁
changeOrigin:true,//控制服务器收到的响应头host字段的值(欺骗后端是自家请求的数据)
pathRewrite:{'^/api':''}//重写请求路径
}),
proxy('/api1',{
target:'http://localhost:5001',
changeOrigin:true,
pathRewrite:{'^/api':''}
})
)
}
//文件使用
//http://localhost:3000如果在3000服务器中没有找到改文件就会走setupProxy.js
axios.get('http://localhost:3000/api/student').then(
response =>{console.log('成功了',response.data)}
error = >{console.log('失败了',error)}
)
axios.get('http://localhost:3000/api2/car').then(
response =>{console.log('成功了',response.data)}
error = >{console.log('失败了',error)}
)
优点:可以配置多个代理,可以灵活的控制请求是否走代理
缺点:配置繁琐,前端请求资源时必须加前缀
引入bootsrtrap
- 在public下创建一个css文件夹,把css放进去
- 在public下的index.html中link引入
- 拓展知识点:
消息订阅与发布(组件间通信)
先订阅在发布,适用于任意组件间通信,记得取消订阅
- 工具库:PubSubJS
- 下载: npm i pubsub-js --save
- 使用:
- import PubSub from ‘pubsub-js’//引入
- PubSub.subscribe(‘delete’,function(msg,data){})//订阅(谁要谁订阅)
- PubSub.publish(‘delete’,data)//发布消息
注意:订阅需要在componentDidMount,如果不写msg可以用_进行占位
拓展:fetch(关注分离的设计思想)
特点:
- fetch:原生函数,不在使用XmlHttpRequest对象提交ajax请求
- 老版本浏览器可能不支持
SPA应用
- 单页 Web应用(single page web application,spa)
- 整个应用只有一个完整的页面
- 点击页面中的链接不会刷新页面,只会做页面的局部刷新
- 数据都需要通过ajax请求获取,并在前段异步展示
路由
什么是路由?
- 一个路由就是一个映射关系(key.value)
- key为路径。value可能是function或component
路由分类
- 后端路由
1. 理解:value是function,用来处理客户端提交的请求
2. 注册路由:router.get(path,function(req,res){})
3. 工作过程:当node接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求。返回响应数据 - 前端路由
1. 浏览器端路由。value是component。用于展示页面内容
2. 注册路由:
3. 工作过程:当浏览器的path为/test时,当前路由组件就会变为Test组件
react-router的理解
- react的一个插件库
- 专门用来实现一个SPA引用
- 基于react的项目基本都会用到此库
react-router-dom相关API
路由(route):路由器上面的天线或者后面的插口
路由器(router)77
- 下载:npm i react-router-dom@5
- 在使用路由的组件中引入import { Link ,Route,NavLink} from ‘react-router-dom’//NavLink可以追加一个类名
- 在index.js中引入import { BrowserRouter} from ‘react-router-dom’将render里的app组件用
<BrowserRouter>
包住 <Link to="/about"></Lingk>
//to里面不要首字母大写<NavLink to="/about" activeClassName="active"></NavLingk>
- 引入两个组件
- 注册路由:
<Route path="/about" component={About}/>
//About—这是引入组件的名称
路由组件和一般组件
5版本路由组件和一般组件不一样
最新版的react-router-dom输出和普通组件一样
区别:
案例navlink封装
NavLink与封装NavLink
- NavLink可以实现路由链接的高亮,通过activeClassName指定样式名
- 标签体内容是一个特殊的标签属性
- 通过this.props.children可以获取标签体内容
switch
5版本的react-router-dom是这样6版本以上的已经是routes
switch什么时候用?当多个route的时候用 这个标签会优先匹配最上面的,下面的就不显示了(不加的时候是都显示的)
- 通常情况下,path和component是一一对应的关系
- Switch可以提高路由匹配效率(单一匹配)
import {Switch,NavLink} from ‘react-router-dom’
<Switch>
<Route path="/about" component={About}/>
<Route path="/about" component={Test}/>
</Switch>
解决样式丢失问题
- public/index.html中引入样式不写
./
写/
-------常用
- publick/index.html中易怒样式时不写
./
写%PUBLIC_URL%
--------常用
- 使用
HashRouter
路由模糊匹配与严格匹配
- 默认使用的是模糊匹配(简单记:【输入的路径】必须包含要【匹配的路径】,且顺序要一致)
<NavLink to="/home/a/b"></NavLink>
- 开启严格匹配:
<Route exact path="/about" component={About}/>
- 严格匹配不要随便开启,需要再开启会导致无法继续匹配二级路由
redirect(重定向)的使用
- 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由
- 具体编码:
<Switch>
<Route path="/about" component={About}/>
<Route path="/home" component={Test}/>
<Redirect to="/about"/>
</Switch>
新版本写法
<Route path="*" element={<Navigate to="/home"/>}/>
二级路由
v5
- 注册子路由时要写上父路由的path值
- 路由的匹配时按照注册路由的顺序进行的
v6
//父
<NavLink to="/home/*">Home</NavLink>
//子
<NavLink to="message">news</NavLink>
路由组件传递params参数
- params参数
路由链接(携带参数):<Link to="/demo/test/tom/18">详情</Link>
注册路由(声明接收):<Route path="/demo/test/:name/:age" component={Test}/>
接收参数:const {id,title} = this.props.match.params
案例
向路由组件传递search参数
- search参数
路由链接(携带参数):<Link to="/demo/test/tom/18">详情</Link>
注册路由(无需声明,正常注册即可):<Route path="/demo/test” component={Test}>
接收参数:const {search} = this.props.location
备注:获取到的search是urlencoed编码字符串,需要借助querystring解析
向路由组件传递state参数
- state参数
路由链接(携带参数):<Link to={{path:'/demo/test',state:{name:'tom',age:18}}>详情</Link>
注册路由(无需声明,正常注册即可):<Route path="/demo/test" compoennt={Test}/>
接收参数:this.props.location.state
备注:刷新也可以保留住参数 注意返回值要||{}
push和replace
push有痕迹默认开启的是push
replace无痕迹,<Link replace to={{path:'/demo/test',state:{name:'tom',age:18}}>详情</Link>
编程式路由导航
借助this.props/history对象上的API对操作路由跳转、前进、后退
——this.props.history.push()
——this.props.history.replace()
——this.props.history.goBack()
——this.props.history.goForward()
——this.props.history.go()
withRouter
将一般组件加工为具备路有组件的特有的API—— withRouter返回值是一个新组件
BrowserRouter与Hash
antd
https://3x.ant.design/docs/react/introduce-cn
- 下载:
npm i antd --save
- 引入:jsx文件里面写
import { Button, DatePicker, version } from "antd";
——需要啥引用啥
import "antd/dist/antd.css";
拓展:移动端ui——vantUI
按需引入
https://3x.ant.design/docs/react/use-with-create-react-app-cn
redux
以求和案例引出的步骤
- 下载:
npm i redux --save
- 使用:
//创建redux文件夹-》1. store.js文件2.count_reducer.js
//store.js
//该文件专门用于暴露一个store对象,整个应用只有一个store对象
//引入createStore,专门用于创建redux最为核心的store对象
import { createStore} from 'redux'
//引入为Count组件服务的reducer
import countReducer from './count_reducer'
//暴露store
export default state = createStore(countReducer)
//count_reducer.js
//1.改文件是用于创建一个为count组件服务的reducer,reducer的本质就是一个函数
//2.reducer函数会接收两个参数,分别为:之前的状态`preState`和动作对象`action`
//这里面不写判断只写最后加工的结果--判断写在需要调用这个store的组件方法里面
const initState = 0
export default function countReducer(preState=initState ,action){
//从action对象中获取:type、data
const {type,data} = action
switch (type){
case 'increment'//如果是加
return preState+data
case 'increment'//如果是减
return preState+data
default
return preState
}
}
求和总结
redux简介
redux是什么
- redux是一个专门用于做
状态管理
的js库,不是react插件库 - 他可以在react、angle、vue等项目中,但基本与react配合使用
- 作用集中式管理react应用中多个组件共享的状态
什么情况下使用redux
- 某个组件的状态,需要让其他组件可以随时拿到(共享)
- 一个组件需要改变另一个组件的状态(通信)
- 总体原则:能不用就不用,如果不用比较吃力才考虑使用
redux原理图
redux的三个核心概念
action
- 动作对象
- 包含两个属性
1. type:标识属性,值为字符串,唯一,必要属性
2. data:数据属性,值类型任意,可选属性 - 栗子:
{type:'ADD_STUDENT',data:{name:"tom",age:18}}
reducer
- 用于初始化状态、加工状态
- 加工时,根据旧的state和action,产生新的state的
纯函数
store
- 将state、action、reducer练习在一起的对象
- 如何得到此对象
import {createStore} from 'redux
import reduce from './reducers
const store = createStore(reducer)
- 此对象的功能
getState()
得到state
duspatch(action)
分发action
,触发reducer
调用,产生新的state
subscribe(listener)
注册监听,当产生了新的state
时,自动调用
求和案例完整版
异步action
- objec{}——同步
- function——异步
react-redux
基本使用
- 明确两个概念
1. UI组件:不能使用任何redux的api,只负责页面的呈现、交互等
2. 容器组件:负责和redux通信,将结果交给UI组件 - 如何创建一个容器组件——靠react-redux的connect函数
1. connect(mapStateTopProps,mapDispatchToProps)(UI组件)
2. -mapStateTopProps(映射状态,返回值是一个对象)
3. -mapDispatchToProps(映射操作状态的方法,返回值是一个对象) - 备注1:容器组件中的store是靠props传进去的,而不是在容易组件中直接引入
- 备注2:mapDispatchToProps也可以是一个对象
求和案例
react-redux求和案例优化
优化1
优化2
优化3
优化总结
- 容器组件和UI组件整合一个文件
- 无需自己给容器组件传递store,给
<App/>
包裹一个<Provider store={store}>
即可 - 使用了react-redux后不用再自己检测redux中状态的改变了,容器组件可以自动完成这个工作
- mapDispatchToProps也可以简单的写成一个对象
- 一个组件要和redux“打交道”要经过哪几步?
1. 定义好UI组件------不暴露
2. 引入connect荣盛城一个容器组件,并暴露,写法如下
connect(state=>({key,value})//映射状态,
{key:xxxxAction}
)(UI组件)
3. 在UI 组件中通过this.props.xxxx读取和操作状态
数据共享
- 定义一个person组件,和count组件通过redux共享组数据
- 为person组件编写:reducer和count的reducer要使用combinReducers进行合并
- 重点:person的reducer和count的reducer要使用combineReducers进行合并,合并后的总状态是一个对象
- 交给store的是中reducer,最后注意在组件中去取出状态的时候,记得取到位
纯函数
- 一类别的函数,只要是同样的输入(实参),必定得到同样的输出(返回)
- 必须遵守以下一些约束
- 不得改写参数的数据
- 不会产生任何副作用,例如网络请求、输入和输出设备
- 不能调用Date.now()或者Math.random()等不纯的方法
- redux的reducer函数必须是一个纯函数
redux开发者工具
在谷歌商城下载redux插件并应用
- npm i redux-devtools–extension
- 在store中配置
import {composeWithDevTools} from 'redux-devtools-extension'
const store = createStore(allReducer,composeWithDevTools(applyMiddleware(thunk)))
setState
lazy
hooks
fragment
context
purecomponent
render props
错误边界
组件间通信总结
reactrouter6