react
本地模式
react 是什么
React 起源于 Facebook
React 是一个用于构建用户界面的 javascript 库。
什么是虚拟Dom
虚拟dom相当于在js和真实dom中间加了一个缓存。基于React进行开发时所有的DOM构造都是通过虚拟DOM进行,每当数据变化时,React都首先重新构建整个DOM树(减少页面更新次数),然后React将当前整个DOM树和上一次的DOM树进行对比(DOM Diff算法-最小化页面重绘),得到DOM结构的区别,然后仅仅将需要变化的部分进行实际的浏览器DOM更新。
虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能。
什么是调和?
将Virtual(虚拟)DOM树转换成actual(真实)DOM树的最少操作的过程称为调和 。
什么是React diff算法?
diff算法是调和的具体实现。
react 特点
声明式设计 −React采用声明范式,可以轻松描述应用。(开发者只需要声明显示内容,react就会自动完成)
高效 −React通过对DOM的模拟,最大限度地减少与DOM的交互。
灵活 −React可以与已知的库或框架很好地配合。
组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。(把页面的功能拆分成小模块–每个小模块就是组件)
单向数据流-- React是单向数据流,数据主要从父节点传递到子节点(通过props)。如果顶层(父级)的某个props改变了,React会重渲染所有的子节点
组件的特点
强 内 聚
弱 耦 合
提高代码复用率:组件将数据和逻辑进行封装。
降低测试难度:组件高内聚低耦合(各个元素高集成度低关联性),很容易对单个组件进行测试。
代码的复杂程度:直观的语法,可以极大提高可读性。
搭建环境
react.js文件是创建React元素和组件的核心文件,
react-dom.js文件用来把React组件渲染为DOM,此文件依赖于react.js文件,需在其后被引入。
Babel的主要用途是将ES6转成ES5 同时可以把JSX 语法转换新标准的JavaScript代码让现今浏览器兼容的代码
下载 cnpm install --save react babel-standalone react-dom
在html文件中引用相关依赖包(注意顺序千万不能错)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 注意:下载好的文件在node_modules目录。
1.找到react目录,找到这个目录下的umd目录下react.development.js;
2.在react-dom/umd目录下找到react-dom.development.js
3.node_modules目录下找到babel-standalone目录下的babel.js -->
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<!-- 页面中需要有一个div容器,容器中的内容都会被React Dom所管理。
这个容器叫做根DOM节点 -->
<div id="demodiv">
</div>
<!-- 让babel知道他要处理哪些地方 -->
<script type="text/babel">
let com=<h1>你好么么哒</h1>
// 注意大小写
ReactDOM.render(com,document.querySelector("#demodiv"))
</script>
</body>
</html>
jsx
JSX=javascript xml就是Javascript和XML结合的一种格式。是JavaScript 的语法扩展。 React推荐在 React 中使用 JSX 来描述用户界面。当遇到<,JSX就当HTML解析,遇到{就当JavaScript解析。
jsx优点:
JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。
它是类型安全的,在编译过程中就能发现错误。
使用 JSX 编写模板更加简单快速。
jsx 插入变量
直接在你想插入的地方 使用{变量}
<script type="text/babel">
// 遇到< 当html解析 遇见{当js解析
let text="123321"
let com=<h1>你好么{text}么哒</h1>
ReactDOM.render(com,document.querySelector("#demodiv"))
</script>
坑1 必须按照w3c规范
// Jsx中的HTML标签必须按照w3c规范来写 标签必须闭合
let com=<input type="text"/>
坑2 jsx中多行标签必须用父容器包裹
let com=(
<div>
<h1>你好</h1>
<h1>你坏</h1>
</div>
)
坑3 注释
在注释的时候使用 {/ * 注释内容 */}
let com=(
<div>
{ /*我是注释*/}
我是内容
</div>
)
坑4 外部js文件
<div id="demodiv"></div>
<!-- 外置js写法必须必须必须必须必须 在引用的时候写上type类型为babel -->
<script src="js.js" type="text/babel"></script>
react中属性插入变量
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 注意:下载好的文件在node_modules目录。
1.找到react目录,找到这个目录下的umd目录下react.development.js;
2.在react-dom/umd目录下找到react-dom.development.js
3.node_modules目录下找到babel-standalone目录下的babel.js -->
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv">
<h1>属性插变量</h1>
</div>
<script type="text/babel">
let text="点我去百度"
let ahref="http://www.baidu.com"
let com=(
<div>
{
/*
html的属性语法是属性="属性值"
jsx中也说了 必须严格验证w3c规范来写
*/
}
<a href={ahref}>{text}</a>
</div>
)
ReactDOM.render(com,document.querySelector("#demodiv"))
</script>
</body>
</html>
设置样式
行内样式
贼恶心 但是必须要知道
类样式
必须要用className
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 注意:下载好的文件在node_modules目录。
1.找到react目录,找到这个目录下的umd目录下react.development.js;
2.在react-dom/umd目录下找到react-dom.development.js
3.node_modules目录下找到babel-standalone目录下的babel.js -->
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
<style>
.demoh{
color:pink;
}
</style>
</head>
<body>
<div id="demodiv">
</div>
<script type="text/babel">
let com=(
<div>
<h1>行内样式</h1>
{/*
在jsx中设置样式必须是一个对象对象对象对象对象
外面的{}是jsx解析js 里面的{}是对象的语法
多个样式单词 需要把-去掉并且把之后的单词首字母大写
*/}
<h1 style={{color:"red",backgroundColor:"yellow"}}>修改我的样式啊!!!!</h1>
<h1>class类样式</h1>
{/*
传统的html+css+js或者是vue中设置类样式都是class属性
但是但是
在react中引用class是js的关键字
所以在react中如果要设置class 那么必须必须必须必须必须 使用className来替代
*/}
<h1 className="demoh">我是class类样式的例子</h1>
</div>
)
ReactDOM.render(com,document.querySelector("#demodiv"))
</script>
</body>
</html>
便利列表
使用map()进行便利
arr.map((v,i)=>{
return (
<li key={i}>{v}</li>
)
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 注意:下载好的文件在node_modules目录。
1.找到react目录,找到这个目录下的umd目录下react.development.js;
2.在react-dom/umd目录下找到react-dom.development.js
3.node_modules目录下找到babel-standalone目录下的babel.js -->
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
<style>
.demoh{
color:pink;
}
</style>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
let arr=["ez",'NOC','MF',"vn"]
let obj=[
{name:"xixi1",age:181},
{name:"xixi2",age:182},
{name:"xixi3",age:183},
{name:"xixi4",age:184},
{name:"xixi5",age:185},
{name:"xixi6",age:186}
]
let com=(
<div>
<h1>便利基本数组</h1>
<ul>
{
arr.map((v,i)=>{
return (
<li key={i}>{v}</li>
)
})
}
</ul>
<h1>便利数组对象</h1>
<table border="1">
<tbody>
{
obj.map((v,i)=>{
return (
<tr>
<td>{v.name}</td>
<td>{v.age}</td>
</tr>
)
})
}
</tbody>
</table>
</div>
)
ReactDOM.render(com,document.querySelector("#demodiv"))
</script>
</body>
</html>
便利对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 注意:下载好的文件在node_modules目录。
1.找到react目录,找到这个目录下的umd目录下react.development.js;
2.在react-dom/umd目录下找到react-dom.development.js
3.node_modules目录下找到babel-standalone目录下的babel.js -->
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
<style>
.demoh{
color:pink;
}
</style>
</head>
<body>
<div id="demodiv"> </div>
<script type="text/babel">
let obj={
name:"xixi",
age:18,
sex:"男",
love:"女"
}
// [name,age,sex,love]
// 因为我们便利出来的v是一个变量但是在对象取值的方式中打点不能取变量所以要用另外一种取值方式[]
let com=(
<div>
{
Object.keys(obj).map((v,i)=>{
return (
<h1>{obj[v]}</h1>
)
})
}
</div>
)
ReactDOM.render(com,document.querySelector("#demodiv"))
</script>
</body>
</html>
扩展小知识—render重新渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
let arr=[111,2222,33333,44444,555555,66666]
// 创建一个变量用来保存你点了谁
let num=-1
// 进行便利
function list(){
let newhtml= arr.map((v,i)=>{
return (
// 在便利出来的内容上添加事件 但是要注意要用驼峰写法i
<h1 key={i} onClick={()=>{num=i;render()}} style={{color:i==num?'red':''}}>{v}</h1>
)
})
// 千万不要忘了return 引用调用这个函数的时候需要返回便利出来的jsx
return newhtml
}
function render(){
ReactDOM.render(list(),document.getElementById("demodiv"))
}
render()
</script>
</body>
</html>
组件—面向组件编程
react创建组件的方式有两种 两种都很重要工作的时候 可能都会用
组件的本质 ---- 自定义标签
无状态组件/函数组件/工厂方式组件
组件 首字母大写 首字母大写 首字母大写
基本创建
// 创建无状态组件
// 首字母大写
function Com(){
// 必须return你想要的jsx
return (
<div>
我是一个组件
</div>
)
}
ReactDOM.render(<Com/>,document.getElementById("demodiv"))
父子组件
父子组件就是在一个父组件中调用子组件
<div id="demodiv"></div>
<script type="text/babel">
// 创建无状态组件
// 首字母大写
function Zi(){
// 必须return你想要的jsx
return (
<div>
我是一个组件
</div>
)
}
function Fu(){
return (
<div>
fufufufuffufufufufuf
<Zi/><Zi/><Zi/><Zi/><Zi/><Zi/>
</div>
)
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
类组件
创建一个class 并起名字 继承(extends)React.Component 在其中render一个方法 return你的jsx
class 你的类名(组件名) extends React.Component{
render(){
return (
你的jsx
)
}
}
实例:
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Mycom extends React.Component{
render(){
return (
<div>我是一个组件</div>
)
}
}
ReactDOM.render(<Mycom/>,document.getElementById("demodiv"))
</script>
父子组件
父子组件
父子组件
父子组件
父子组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Mycom extends React.Component{
render(){
return (
<div>我是一个组件</div>
)
}
}
class Myfu extends React.Component{
render(){
return (
<div>
fufuffufufufufufufu
<Mycom/><Mycom/><Mycom/><Mycom/><Mycom/>
</div>
)
}
}
ReactDOM.render(<Myfu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
props
使用props就可以从外部向组件内部进行数据传递 完成父组件传值给子组件
注意:Props对于使用它的组件来说,是只读的。一旦赋值不能修改。也就是说props的值是不可变的只能在渲染的时候传入无法动态赋值。
props基本语法
函数组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
// 函数组件使用props 就需要把props当成形参传入即可
function Zi(props){
return (
<div>
我是一个组件-----{props.name}
</div>
)
}
function Fu(){
return (
<div>
fufuffufufufufufufu
{/* 在子组件被调用的地方 把props传递的值当成一个属性进行传递*/}
<Zi name="你好我是传递的数据"/>
</div>
)
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
类组件
他的props使用是 直接使用this.props.xxx来进行创建
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Mycom extends React.Component{
render(){
return (
<div>
我是一个组件
{/*类组件创建props*/}
<h1>{this.props.name}</h1>
</div>
)
}
}
class Myfu extends React.Component{
render(){
return (
<div>
fufuffufufufufufufu
<Mycom name="我是传递的数据么么哒!!!!!"/>
</div>
)
}
}
ReactDOM.render(<Myfu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
小扩展
- 因为如果由多个props那么我就会写很多变this.props 很麻烦
- 所以我可以直接在组件中进行结构方便页面使用
class Mycom extends React.Component{
render(){
// 因为如果由多个props那么我就会写很多变this.props 很麻烦
// 所以我可以直接在组件中进行结构方便页面使用
let {name,age,sex,love} =this.props
return (
<div>
我是一个组件
{/*类组件创建props*/}
<h1>{name}</h1>
<h1>{age}</h1>
<h1>{sex}</h1>
<h1>{love}</h1>
</div>
)
}
}
class Myfu extends React.Component{
render(){
return (
<div>
fufuffufufufufufufu
<Mycom name="我是传递的数据么么哒!!!!!" age="18" sex="男" love="女"/>
</div>
)
}
}
ReactDOM.render(<Myfu/>,document.getElementById("demodiv"))
props默认值
函数组件
组件名.defaultProps={
你要设置默认值的props:默认值
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
// 函数组件使用props 就需要把props当成形参传入即可
function Zi(props){
return (
<div>
我是一个组件-----{props.name}
</div>
)
}
// props默认值
Zi.defaultProps={
name:"我是name的默认值"
}
function Fu(){
return (
<div>
fufuffufufufufufufu
<Zi/>
</div>
)
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
类组件
与函数组件一样使用defaultProps
// 类组件也是使用defaultProps 来进行默认值的设置
Mycom.defaultProps={
name:"你好我是默认值*_!"
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv">
</div>
<script type="text/babel">
class Mycom extends React.Component{
render(){
let {name}=this.props
return (
<div>
我是类组件---{name}
</div>
)
}
}
// 类组件也是使用defaultProps 来进行默认值的设置
Mycom.defaultProps={
name:"你好我是默认值*_!"
}
ReactDOM.render(<Mycom name="1111111"/>,document.getElementById("demodiv"))
</script>
</body>
</html>
props验证
在react15.5版本之后 props验证已经在核心包中移除了所以要使用 需要但需下载prop-types(单词不要错了)
下载: npm install --save prop-types
官网:https://react.docschina.org/docs/typechecking-with-proptypes.html
函数组件props验证
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
<script src="node_modules/prop-types/prop-types.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
// 函数组件使用props 就需要把props当成形参传入即可
function Zi(props){
return (
<div>
我是一个组件-----{props.name}
</div>
)
}
let num=123;
// props验证
Zi.propTypes={
name:PropTypes.number
}
function Fu(){
return (
<div>
fufuffufufufufufufu
<Zi name={num}/>
</div>
)
}
ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
类组件验证
同函数组件
扩展
刚才在类组件中我们多次调用了this.props 解决方式是 我们使用解构来进行快速赋值
但是有个问题 就是在传递参数的时候也很麻烦
那么可以使用扩展运算符进行一次传递多个数据
<Mycom {...obj}/>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Mycom extends React.Component{
render(){
let {name,age,sex,love} =this.props
return (
<div>
我是一个组件
{/*类组件创建props*/}
<h1>{name}</h1>
<h1>{age}</h1>
<h1>{sex}</h1>
<h1>{love}</h1>
</div>
)
}
}
let obj={
name:"xixi",
age:99,
sex:"nan",
love:"nv"
}
class Myfu extends React.Component{
render(){
return (
<div>
fufuffufufufufufufu
{/*一次传递多个props可以使用扩展运算符*/}
<Mycom {...obj}/>
</div>
)
}
}
ReactDOM.render(<Myfu/>,document.getElementById("demodiv"))
</script>
</body>
</html>
state–状态机制
在react中开发者只需要关心数据。数据改变页面就会发生改变
数据等同于状态。状态改变-页面绑定的数据就由react进行改变
组件被称之为“状态机”,视图与状态一一对应
基本语法
state
{/*使用state数据*/}
<h1>我是数据是----{this.state.name}</h1>
setState()
{/*react状态的修改必须使用this.setState()进行修改*/}
<button onClick={()=>{this.setState({name:"我变了"})}}>点我改变</button>
// state状态机制
class Mycom extends React.Component{
constructor(props){
super(props)
// 创建变量数据
this.state={
name:"xixi",
arr:[111,222,333],
obj:{
sex:"男"
}
}
}
render(){
return (
<div>
{/*使用state数据*/}
<h1>我是数据是----{this.state.name}</h1>
{/*react状态的修改必须使用this.setState()进行修改*/}
<button onClick={()=>{this.setState({name:"我变了"})}}>点我改变</button>
</div>
)
}
}
ReactDOM.render(<Mycom/>,document.getElementById("demodiv"))
setState()深入讨论
异步的
// 状态-----setState---是异步的
class Com extends React.Component{
constructor(props){
super(props)
this.state={
text:"你好"
}
}
fun=()=>{
// this.setState({
// text:"你坏!!!!!!"
// })
// 为了证明setState是异步的 那么我们可以在修改之后console一下修改的数据
// 如果这个打印的数据是修改之后的 那么也就能证明他是同步的 反之他就是异步的
// console.log(this.state.text)
// 分割线分割线分割线分割线分割线分割线分割线分割线分割线分割线分割线
// 我就是想当数据改变之后在打印出改变之后的结果 怎么办?
this.setState({
text:"你坏!!!!!!22222"
},()=>{
console.log(this.state.text)
})
}
render(){
return (
<div>
<h1>{this.state.text}</h1>
<button onClick={this.fun}>点我修改</button>
</div>
)
}
}
ReactDOM.render(<Com/>,document.getElementById("demodiv"))
自动调用render重新渲染
在没有学过state之前 我们如果想修改数据并且让页面改变 我们需要手工让render重新渲染
因为当我们调用了setState之后他就会自动的触发render渲染从而让页面的数据根据状态的改变而随之发生改变
总结
当调用了setState之后发生了什么?
当调用了setState之后首先他是进行state状态修改的 但是它在修改的过程中是一个异步操作 他会把所有的修改任务方一个执行缓冲区中进行等待 等待着统一数据修改 修改之后也会自动调用render方法进行页面重新渲染(自动调用render进行了一个调和的过程)
小扩展—插入字符串标签
dangerouslySetInnerHTML = {{ __html:你要插入的字符串 }}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Com extends React.Component{
constructor(props){
super(props)
// this.state={
// demohtml:"<h1>我是字符串标签</h1>"
// }
this.demohtml="<h1>我是字符串标签</h1>"
}
render(){
return (
<div>
<div>
{this.demohtml}
</div>
{/*
上面的写法直接把一个字符串标签展示是会原样输出的
dangerouslySetInnerHTML = {{ __(双底杠)html:你要插入的字符串 }}
*/}
<div dangerouslySetInnerHTML={{__html:this.demohtml}}></div>
</div>
)
}
}
ReactDOM.render(<Com/>,document.getElementById("demodiv"))
</script>
</body>
</html>
ref
React提供的这个ref属性(不能在无状态组件上使用 ref 属性,因为它们没有实例)表示为对组件真正实例的引用其实就是ReactDOM.render()返回的组件实例
ReactDOM.render()渲染组件时返回的是组件实例;而渲染dom元素时,返回是具体的dom节点。
一句话总结:
标识组件内部的元素
使用
字符串
回调函数
createRef
class Com extends React.Component{
constructor(props){
super(props)
// 1.创建createref
this.myRef=React.createRef()
}
funa=()=>{
// 字符串方式
this.refs.demoref.style.color="red";
}
funb=()=>{
// 回调函数方式ref
this.demoh.style.backgroundColor="pink";
}
func=()=>{
// createref方式ref
console.log(this.myRef.current);
this.myRef.current.style.fontSize="100px";
}
render(){
return (
<div>
<h1 ref="demoref">字符串方式使用ref</h1>
<button onClick={this.funa}>点我修改上面的颜色</button>
<hr/>
{/* <h1 ref={(形参随便写代表的就是当前这个元素)=>{this.你创建个变量=形参}}>回调函数方式创建ref</h1>*/}
<h1 ref={(xiaoming)=>{this.demoh=xiaoming}}>回调函数方式创建ref</h1>
<button onClick={this.funb}>点我修改上面的背景颜色</button>
<hr/>
{/*2挂载*/}
<h1 ref={this.myRef}>createRer的方式</h1>
<button onClick={this.func}>点我修改上面的字体大写</button>
</div>
)
}
}
ReactDOM.render(<Com/>,document.getElementById("demodiv"))
React受控组件
React负责渲染表单的组件。同时仍然控制用户后续输入时所发生的变化。值是来自于state控制的 输入表单元素称为“受控组件”。
React事件处理
React事件绑定属性的命名采用小驼峰式写法。
绑定函数的过程中不加() 否则函数会立即执行
阻止事件默认行为与阻止冒泡
同js原生方式 例如:React中阻止默认行为使用preventDefault();
this修改
方式1:bind
通过bind方法进行原地绑定,从而改变this指向
<div>
<h1>方式1:通过bind方法进行原地绑定,从而改变this指向 ----- {this.state.text}</h1>
<button onClick={this.funb.bind(this)}>点我修改数据</button>
</div>
// 方式1:通过bind方法进行原地绑定,从而改变this指向
funb(){
this.setState({
text:"你好么么哒bbbb"
})
}
方式2:通过创建箭头函数
<div>
<h1>方式2:通过创建箭头函数 ----- {this.state.text}</h1>
<button onClick={this.func}>点我修改数据</button>
</div>
// 方式2:通过创建箭头函数
func=()=>{
this.setState({
text:"你好么么哒cccc"
})
}
方式3:在constructor中提前对事件进行绑定
constructor(props){
super(props)
this.state={
text:"你好"
}
// 提前绑定
this.fund=this.fund.bind(this)
}
<div>
<h1>方式3:在constructor中提前对事件进行绑定 ----- {this.state.text}</h1>
<button onClick={this.fund}>点我修改数据</button>
</div>
// 方式3:在constructor中提前对事件进行绑定
fund(){
this.setState({
text:"你好么么哒ddddd"
})
}
方式4-1:将事件调用的写法改为箭头函数的形式
方式4-2:将事件调用的写法改为箭头函数调用函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Com extends React.Component{
constructor(props){
super(props)
this.state={
text:"你好"
}
// 提前绑定
this.fund=this.fund.bind(this)
}
// 错误的写法
funa(){
this.setState({
text:"你好么么哒"
})
}
// 方式1:通过bind方法进行原地绑定,从而改变this指向
funb(){
this.setState({
text:"你好么么哒bbbb"
})
}
// 方式2:通过创建箭头函数
func=()=>{
this.setState({
text:"你好么么哒cccc"
})
}
// 方式3:在constructor中提前对事件进行绑定
fund(){
this.setState({
text:"你好么么哒ddddd"
})
}
// 方式4-1:将事件调用的写法改为箭头函数的形式
// 方式4-2:将事件调用的写法改为箭头函数调用函数
funf(){
this.setState({
text:"你好么么哒fffff"
})
}
render(){
return (
<div>
<div>
<h1>错误的写法 ----- {this.state.text}</h1>
<button onClick={this.funa}>点我修改数据</button>
</div>
<div>
<h1>方式1:通过bind方法进行原地绑定,从而改变this指向 ----- {this.state.text}</h1>
<button onClick={this.funb.bind(this)}>点我修改数据</button>
</div>
<div>
<h1>方式2:通过创建箭头函数 ----- {this.state.text}</h1>
<button onClick={this.func}>点我修改数据</button>
</div>
<div>
<h1>方式3:在constructor中提前对事件进行绑定 ----- {this.state.text}</h1>
<button onClick={this.fund}>点我修改数据</button>
</div>
<div>
<h1>方式4-1:将事件调用的写法改为箭头函数的形式 ----- {this.state.text}</h1>
<button onClick={()=>{this.setState({text:"你好么么哒eeeee"})}}>点我修改数据</button>
</div>
<div>
<h1>方式4-2:将事件调用的写法改为箭头函数调用函数 ----- {this.state.text}</h1>
<button onClick={()=>{this.funf()}}>点我修改数据</button>
</div>
</div>
)
}
}
ReactDOM.render(<Com/>,document.getElementById("demodiv"))
</script>
</body>
</html>
函数参数传递
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="node_modules/react/umd/react.development.js"></script>
<script src="node_modules/react-dom/umd/react-dom.development.js"></script>
<script src="node_modules/babel-standalone/babel.js"></script>
</head>
<body>
<div id="demodiv"></div>
<script type="text/babel">
class Com extends React.Component{
fun=(val)=>{
console.log(val)
}
render(){
return (
<div>
{/*事件参数传递方式1 使用bind方式*/}
<button onClick={this.fun.bind(this,"我是参数1")}>点我打印内容</button>
<hr/>
{/*事件参数传递方式1 使用箭头函数的方式调用函数*/}
<button onClick={()=>{this.fun("哈哈")}}>点我打印内容</button>
</div>
)
}
}
ReactDOM.render(<Com/>,document.getElementById("demodiv"))
</script>
</body>
</html>
TODOLIST(JSX)——修改数据需要setState
- 一个输入框+添加按钮(绑定事件)——如何得到输入框的值???
- ref方式
- 回调函数方式——ref={(xingcan)=>{this.demoref=xingcan}}——console.log(this.demoref.value)
- createRef方式——this.myRef=React.createRef()——ref={this.myRef}——console.log(this.myRef.current.value)
import React, { Component } from 'react'
export default class todolist extends Component {
constructor(props){
super(props)
// this.myRef=React.createRef()
this.state={
arr:[
{title:1111},
{title:2222},
{title:3333},
{title:4444},
{title:5555},
{title:6666}
]
}
}
list=()=>{
return this.state.arr.map((v,i)=>{
return (
<li key={i}>
{v.title}
<button onClick={this.edit.bind(this,i)}>编辑</button>
<button onClick={this.del.bind(this,i)}>删除</button>
</li>
)
})
}
render() {
return (
<div>
{/* 回调函数方式 */}
<input type="text" ref={(val)=>{this.inputval=val}}/>
<button onClick={this.addd}>添加</button>
{/* creatRef方式
<input type="text" ref={this.myRef}/>
<button onClick={this.add}>添加</button> */}
<ul>
{this.list()}
</ul>
</div>
)
}
添加——push
//添加:
//1.得到输入框的值
//2.添加到数组中:修改数据用setState()来修改
addd=()=>{
console.log(this.inputval.value)
let addarr=this.state.arr
addarr.push({title:this.inputval.value})
this.setState({
arr:addarr
})
this.inputval.value=""
}
// add=()=>{
// console.log(this.myRef.current.value)
// }
删除——splice(n,1)
//删除:绑定事件。
//1.得到点击数据;确定删除谁(函数实参传递)
// 2.从数组中删除(也必须使用setState来删除)
del=(n)=>{
console.log(n)
let delarr=this.state.arr
delarr.splice(n,1)
this.setState({
arr:delarr
})
}
编辑——
如何得到prompt输入框的内容:let val=window.prompt(“xxxx”)
//编辑:确定:返回输入框的内容;取消不做操作;
edit=(n)=>{
console.log(n);
// console.log(window.prompt("请输入修改内容"))======输出输入框的内容但是不能写,会弹出两次
let inputval=window.prompt("请输入修改内容")
console.log(inputval);======输出输入框的内容
if(inputval){
let editarr=this.state.arr
editarr[n].title=inputval
this.setState({
arr:editarr
})
}
}
脚手架 create-react-app
创建
npm install -g create-react-app 安装脚手架
create-react-app --version 查看版本
create-react-app 项目名 创建项目
cd 项目名 切换到创建好的项目中
npm start 启动运行(所有命令中 只有start可以不加run)
组件
基本使用—组件的创建
新建一个components的文件夹用来容纳组件
在其中创建以.jsx结尾的文件 并写入组件代码
类组件
import React, { Component } from 'react'
export default class home extends Component {
render() {
return (
<div>
你好么么哒 我是一个组件
</div>
)
}
}
函数组件
后面学到hook在说
基本使用—组件的使用
1.引用 ——import Home from ‘./components/home.jsx’;
2.使用
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
// 引用
import Home from './components/home.jsx';
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<React.StrictMode>
{/* 使用 */}
<Home />
</React.StrictMode>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
扩展小知识–空标签
1.就是空标签(了解就好 不要用)
return (
<>
<p>下标:{i}</p>
<h1>值: {v}</h1>
</>
)
2.Fragment 用来包裹代码 但是不参与页面渲染的
先引用
import React, { Component,Fragment } from 'react'
再使用
{ this.state.arr.map((v,i)=>{ return ( <Fragment> <p>下标:{i}</p> <h1>值: {v}</h1> </Fragment> ) })}
props
与本地模式一模一样
import React, { Component } from 'react'
export default class zi extends Component {
render() {
let {name}=this.props
return (
<div>
zizizziziziziziz---{name}
</div>
)
}
}
props 验证——propTypes
state 的使用
他的使用和本地模式一样
创建——this.state={}
使用——this.state.xxxx
修改——this.setState({})
事件
从事件的创建 到this的指向 再到参数的传递 和本地模式一模一样
列表渲染
循环数据和本地模式一模一样
this.props.children
表示当前组件所有的子节点
默认情况下组件的开标签和关标签之间的内容能显示吗?
不能显示
import React, { Component } from 'react'
export default class zi extends Component {
render() {
let {name}=this.props
return (
<div>
ziiiiii———{name}
{/* 表明当前组建的而所有节点 */}
{this.props.children}
</div>
)
}
}
本来不会显示:11111组件内部的数据/22222
加上{this.props.children}之后机会显示
import Fu from "./components/fu.jsx"
import Zi from "./components/zi.jsx"
function App() {
return (
<div className="App">
本来不会显示:11111组件内部的数据/22222
加上{this.props.children}之后机会显示
<Fu>11111组件内部的数据</Fu>
<Zi name={"hhhhh"}>22222</Zi>
</div>
);
}
export default App;
this.props.children的值有三种可能:
1.如果当前组件没有子节点,它就是undefined;
2.如果有一个子节点,数据类型是Object;
3.如果有多个子节点,数据类型就是array。
=======可以对其进行一些操作=================
{this.props.children.map((v,i)=>{
return(
<ul>
<li>no{i}</li>
<li>{v}</li>
</ul>
)
})}
扩展—强制渲染、强制刷新
如果数据没由在state中 而且我还想让数据变了页面也随之发生更新怎么办?
本地模式中 我们可以使用 重新触发render的写法
在脚手架中不能 不能向本地一样
forceUpdate()就是重新调用render渲染。有些变量不在state上,当时你又想达到这个变量更新的时候,刷新render;
import React, { Component } from 'react'
export default class 测试forceupdate extends Component {
constructor(props){
super(props)
this.test="不在状态里面的数据"
}
render() {
return (
<div>
test——{this.test}
<button onClick={()=>{this.test="改了";
console.log(this.test);this.forceUpdate()}}>点我修改</button>
{/* 修改之后页面没有刷新 ——forceupdate()*/}
</div>
)
}
}
组件传值
正传
props
逆传
在react中没有单独的语法来实现逆向传值 他是借由props来实现的
1.通过事件调用一个props接收父组件传递过来的一个函数
import React, { Component } from 'react'
export default class zic extends Component {
render() {
return (
<div>
<h1>组件逆向传值</h1>
{/* 1。逆向传值必须通过事件来触发 */}
<button onClick={this.props.fufun.bind(this,"我是子组件的数据")}>点我把数据传传递给父组件</button>
</div>
)
}
}
2.父组件创建传递给子组件的函数并且加入形参
import React, { Component } from 'react'
import Zic from "./zic.jsx"
export default class fu extends Component {
emit=(text)=>{
console.log(text)
}
render() {
return (
<div>
fufufufufufufufu
<Zic fufun={this.emit}/>
</div>
)
}
}
同胞传值 pubsub-js
下载 : npm install --save pubsub-js
抛出一个自定义事件——PubSub.publish(“事件名”,“数据”)
import React, { Component } from 'react'
// 1.引用pubsub-js
import PubSub from "pubsub-js"
export default class zid extends Component {
fun(){
// 2.抛出一个自定义事件
// PubSub.publish("自定义事件名","数据")
PubSub.publish("xiongpao","我是zid的数据")
}
render() {
return (
<div>
zid
<button onClick={()=>{this.fun()}}>点我把数据给我兄弟</button>
</div>
)
}
}
接收自定义事件——PubSub.subscribe(“监听的事件”,(事件,数据)=>{})
import React, { Component } from 'react'
// 1.引用
import PubSub from "pubsub-js"
export default class zie extends Component {
componentDidMount() {
// 2.监听自定义事件 PubSub.subscribe("监听的事件",(事件,数据)=>{})
PubSub.subscribe("xiongpao",(a,b)=>{
console.log(a)
console.log(b)
})
}
render() {
return (
<div>
zie
</div>
)
}
}
跨组件传值–context 上下文对象
context 上下文对象来实现
context:上下文对象
context很好的解决了跨组件传值的复杂度。可以快速的进行跨组件数据的传递。
想要使用context进行跨组件传值那么就要使用**createContext()**方法同时方法中给我们提供了两个对象:
Provider对象
生产者---->用来生产数据
Consumer对象
消费者---->用来使用数据
1.创建一个上下问对象的文件 并且设置this.props.children
context/index.js
// 容纳上下文对象
import React, { Component } from 'react'
export default class index extends Component {
render() {
return (
<div>
{/* 1.添加this.props.children */}
{this.props.children}
</div>
)
}
}
2.在根里面引用相关的上下文对象组件 并使用
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Home from './components/contextcon/ye.jsx';
// 引用上下文对象
import Index from "./context/index.js"
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<Index>
{/* 使用 */}
<Home />
</Index>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
3.创建上下文对象
// 容纳上下文对象
import React, { Component, createContext } from 'react'
// 创建上下文对象数据
let context=createContext()
let {Provider,Consumer}=context
class Index extends Component {
render() {
return (
<div>
{/* 1.添加this.props.children */}
<Provider value={123}>
{this.props.children}
</Provider>
</div>
)
}
}
export {Index,Consumer}
4 修改根中的组件引用
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Home from './components/contextcon/ye.jsx';
// 引用上下文对象
import {Index} from "./context/index.js"
import reportWebVitals from './reportWebVitals';
ReactDOM.render(
<Index>
{/* 使用 */}
<Home />
</Index>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
5 在组件中使用
import React, { Component } from 'react'
import Fu from "./fu.jsx"
import {Consumer} from "../../context/index.js"
export default class ye extends Component {
render() {
return (
<div>
我是爷爷组件
<Consumer>
{
(value)=>{
return (
<span>{value}</span>
)
}
}
</Consumer>
<Fu/>
</div>
)
}
}
跨层级传值还有一个技术叫redux(后面会由专门的课来上)
高阶组件介绍:(哪里用过高阶组件)
路由——history——找不到——使用高阶组件withrouter
HOC 高阶组件
高阶组件就是一类功能需要被不同的组件公用。
可以复用在react组件中的代码与逻辑 。
HOC–参数是组件同时返回值也是组件
1.创建高阶组件——hoc/index.js
import React, { Component } from 'react'
// HOC---参数是一个组件 返回值还是一个组件
// 因为参数是一个组件所以形参必须大写
let Hocdemo=(Com)=>{
return class index extends Component {
render() {
return (
<div>
<h1>2012hoc</h1>
<Com/>
</div>
)
}
}
}
//暴露在最后面
export default Hocdemo
2.调用——hoc.jsx
引用高阶组件 并且修改暴露到最下面 使用高阶组件(当前组件)
import React, { Component } from 'react'
import Hoc from "../hoc/index.js"
class hoc extends Component {
render() {
return (
<div>
<h1>我是测试hoc的组件</h1>
</div>
)
}
}
export default Hoc(hoc)
高阶组件传递props
默认情况下 如果一旦当前组件使用了HOC那么在进行props正向传值的时候就没有办法接收到数据
所以我们需要在高阶组件中进行数据的传递
//hoc/index.js
import React, { Component } from 'react'
// HOC---参数是一个组件 返回值还是一个组件
// 因为参数是一个组件所以形参必须大写
let Hocdemo=(Com)=>{
return class index extends Component {
render() {
return (
<div>
<h1>2102HOC</h1>
{/* 传递props给组件 */}
<Com {...this.props}/>
</div>
)
}
}
}
export default Hocdemo
//hoc.jsx
import React, { Component } from 'react'
import Hoc from "../hoc/index.js"
class hoc extends Component {
render() {
return (
<div>
<h1>我是测试hoc的组件——{this.props.title}</h1>
</div>
)
}
}
export default Hoc(hoc)
//fu.jsx
import React, { Component } from 'react'
import Hoc from "./hoc.jsx"
export default class fu extends Component {
render() {
return (
<div>
fufufu
<Hoc title="hocprops"/>
</div>
)
}
}
HOC–反向继承
反向继承最核心作用,是渲染劫持(拦截了渲染可以让我们进行条件渲染)。
反向继承就是高阶组件的条件渲染 反向继承就是高阶组件的条件渲染
// 反向继承
import React, { Component } from 'react'
let Hocdemo=(Com,tj)=>{
return class index extends Com {
render() {
if(tj>=18){
return (
<div> <Com/>你一年满可以正常进入</div>
)
}else{
return (
<div>已经进入青少年模式</div>
)
}
}
}
}
export default Hocdemo
//在hoc.jsx中进行传参
export default Hoc(hoc,1)
export default Hoc(hoc,19)
路由
自动创建路由 就不要想了
根据不同的url 来切换对应的组件
实现spa(单页面应用)应用:
整个项目只有一个完整页面
页面切换不会刷新页面(不会感觉页面的闪烁 更加贴近原生应用的体验)
分类
React-Router:提供了一些router的核心API,包括Router, Route, Switch等,但是它没有提供 DOM 操作进行跳转的API。
**React-Router-DOM:**提供了 BrowserRouter, Route, Link等 API,我们可以通过 DOM 的事件控制路由。例如点击一个按钮进行跳转,大多数情况下我们是这种情况,所以在开发过程中,我们更多是使用React-Router-DOM。
路由模式
HashRouter (hash模式)
url中会有个#,例如localhost:3000/#,HashRouter就会出现这种情况,它是通过hash值来对路由进行控制。如果你使用HashRouter,你的路由就会默认有这个#。刷新不会丢失
BrowserRouter(历史记录模式 )
是通过历史记录api来进行路由的切换的很多情况下我们则不是这种情况,我们不需要这个#,因为它看起来很怪,这时我们就需要用到BrowserRouter。刷新会丢失404(上线中会出现问题 本地开发中不会)
基本路由实现
1.下载对应的路由库 react-router-dom
2.引用路由模式在全局中 进行配置
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// 1.引用路由模式
import {BrowserRouter} from "react-router-dom"
ReactDOM.render(
// 2.使用
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
3.创建路由页面组件(在src下新建一个views/pages/随便的名字 在其中创建.jsx结尾的组件)
4.配置路由规则与出口 (在src下创建一个router的文件夹里面创建index.js用来容纳路由出口与规则)
- 使用Route来进行配置 里面两个属性 path路径 component引用的组件
import React, { Component } from 'react'
// 1.引用
import {Route} from "react-router-dom"
// 3.引用路由页面组件
import Home from "../views/home.jsx"
import Phone from "../views/phone.jsx"
import Shop from "../views/shop.jsx"
import User from "../views/user.jsx"
export default class index extends Component {
render() {
return (
<div>
{/* 2.使用 */}
<Route path="/home" component={Home}/>
<Route path="/phone" component={Phone}/>
<Route path="/shop" component={Shop}/>
<Route path="/user" component={User}/>
</div>
)
}
}
5.在全局配置文件中引用路由规则页面
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
// 引用路由规则页面
import App from './router/index.js';
import reportWebVitals from './reportWebVitals';
// 1.引用路由模式
import {BrowserRouter} from "react-router-dom"
ReactDOM.render(
// 2.使用
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
路由导航
声明式
Link: 仅仅是最基础的导航
NavLink : 在基础的导航功能之上添加了动态类名 方便我们设置后续的样式
如果在vscode的终端中启动项目可能会无效 在外部cmd中启动
navlink默认添加的类名: active 如果想修改这个类名
<NavLink activeClassName="你要修改的类名“>
import React, { Component } from 'react'
// 1.引用
import {Route,Link,NavLink} from "react-router-dom"
// 3.引用路由页面组件
import Home from "../views/home.jsx"
import Phone from "../views/phone.jsx"
import Shop from "../views/shop.jsx"
import User from "../views/user.jsx"
export default class index extends Component {
render() {
return (
<div>
<NavLink to="/home">点我去home</NavLink>
<NavLink to="/phone">点我去phone</NavLink>
<NavLink to="/shop">点我去shop</NavLink>
<NavLink to="/user">点我去user</NavLink>
{/* 2.使用 */}
<Route path="/home" component={Home}/>
<Route path="/phone" component={Phone}/>
<Route path="/shop" component={Shop}/>
<Route path="/user" component={User}/>
</div>
)
}
}
编程式
this.props.history.push("/xxxx")进行页面跳转
在这里一定一定要注意 在react中使用路由的编程式导航 一定要记住 默认只能在被路由所管理的页面中使用因为不在路由所管理的页面就没有路由切换属性
以下就是不在路由所管理的页面使用编程式导航
import React, { Component } from 'react'
// 1.引用
import {Route,Link,NavLink} from "react-router-dom"
// 3.引用路由页面组件
import Home from "../views/home.jsx"
import Phone from "../views/phone.jsx"
import Shop from "../views/shop.jsx"
import User from "../views/user.jsx"
export default class index extends Component {
fun=()=>{
// 编程式导航
this.props.history.push("/user")
}
render() {
return (
<div>
<NavLink to="/home">点我去home</NavLink>
<NavLink to="/phone">点我去phone</NavLink>
<NavLink to="/shop">点我去shop</NavLink>
<NavLink to="/user">点我去user</NavLink>
<button onClick={this.fun}>点我去user</button>
{/* 2.使用 */}
<Route path="/home" component={Home}/>
<Route path="/phone" component={Phone}/>
<Route path="/shop" component={Shop}/>
<Route path="/user" component={User}/>
</div>
)
}
}
解决react编程式路由push报错
如果我就是想在不是被路由所管理的页面使用路由的编程式导航怎么办?
使用withRouter这个高阶组件
1.引用withRouter 这个高阶组件
2.修改暴露到最下面 然后使用他
import React, { Component } from 'react'
// 1.引用
import {Route,Link,NavLink,withRouter} from "react-router-dom"
// 3.引用路由页面组件
import Home from "../views/home.jsx"
import Phone from "../views/phone.jsx"
import Shop from "../views/shop.jsx"
import User from "../views/user.jsx"
class index extends Component {
fun=()=>{
// 编程式导航
this.props.history.push("/user")
}
render() {
return (
<div>
<NavLink to="/home">点我去home</NavLink>
<NavLink to="/phone">点我去phone</NavLink>
<NavLink to="/shop">点我去shop</NavLink>
<NavLink to="/user">点我去user</NavLink>
<button onClick={this.fun}>点我去user</button>
{/* 2.使用 */}
<Route path="/home" component={Home}/>
<Route path="/phone" component={Phone}/>
<Route path="/shop" component={Shop}/>
<Route path="/user" component={User}/>
</div>
)
}
}
export default withRouter(index)
更多编程式导航
replace() 替换当前路径
goBack()后退
goForward()前进
exact 精准匹配
另外需要注意一点的是嵌套路由不要加exact属性
render() {
return (
<div>
<NavLink to="/">点我去home</NavLink>
<NavLink to="/phone">点我去phone</NavLink>
<NavLink to="/shop">点我去shop</NavLink>
<NavLink to="/user">点我去user</NavLink>
<button onClick={this.fun}>点我去user</button>
{/* 2.使用 */}
{/* 精准匹配--严格按照路径进行匹配 */}
<Route path="/" exact component={Home}/>
<Route path="/phone" component={Phone}/>
<Route path="/shop" component={Shop}/>
<Route path="/user" component={User}/>
</div>
)
}
404
在路由规则的最下面 使用
Switch 唯一渲染
只渲染当前范围内的一项
redirect 重定向
{/* 2.使用 */}
{/* Switch 唯一渲染 */}
<Switch>
<Route path="/home" component={Home}/>
<Route path="/phone" component={Phone}/>
<Route path="/shop" component={Shop}/>
<Route path="/user" component={User}/>
{/* 重定向 */}
{/* 精准匹配--严格按照路径进行匹配 */}
<Redirect from="/" exact to="/home"/>
{/* 配置404页面 千万记住放在最下面 */}
<Route component={No}/>
</Switch>
路由传参
params
优势 : 刷新地址栏,参数依然存在
缺点 : 只能传字符串,并且,如果传的值太多的话,url会变得长而丑陋。
使用:
1.在路由规则中进行接收变量的设置
<Switch>
<Route path="/home" component={Home}/>
<Route path="/phone" component={Phone}/>
<Route path="/shop" component={Shop}/>
{/* 设置路径接收参数 */}
<Route path="/user/:num" component={User}/>
<Redirect from="/" exact to="/home"/>
{/* 404页面 */}
<Route component={No}/>
</Switch>
2.发送
<Link to="/user/我是params方式传递的数据"></Link>
fun=()=>{
this.props.history.push("/user/btn我是params方式传递的数据")
}
3.接收——this.props.match.params.xxxx
import React, { Component } from 'react'
export default class user extends Component {
render() {
return (
<div>
user--{this.props.match.params.num}
</div>
)
}
}
state
优势:传参优雅地址栏不显示传递的数据,传递参数可传对象;
缺点:刷新地址栏,参数丢失
使用:
1.发送
<Link to={{pathname:"/路径",state:{text:"我是state的路由传参"}}}></Link>
this.props.history.push({pathname:"/路径",state:{text:"我是state的路由传参"}})
2.接收——this.props.location. state.xxxx
import React, { Component } from 'react'
export default class shop extends Component {
render() {
return (
<div>
shop---{this.props.location.state.text}
</div>
)
}
}
二级路由/嵌套路由/多级路由
1.创建路由页面组件
2.创建路由规则
就是在你对应的一级路由页面中使用Route来进行创建
import React, { Component } from 'react'
import {Route,NavLink} from "react-router-dom"
//引入
import Era from "./er/era.jsx"
import Erc from "./er/erc.jsx"
export default class phone extends Component {
render() {
return (
<div>
phone
//路径
<NavLink to="/phone/era">era</NavLink>
<NavLink to="/phone/erc">erc</NavLink>
<Route path="/phone/era" component={Era}/>
<Route path="/phone/erc" component={Erc}/>
</div>
)
}
}
路由render渲染写法
就是给路由在渲染加载之前 有一个可以写逻辑的地方(可以进行一些业务操作 根据指定的结果有选择性的显示或者不显示当前这个路由页面)
{/* 路由的render渲染写法 */}
<Route path="/rc" render={(props)=>{return true?<Rc {...props}/>:<No/> }}/>
redux
redux是专门作状态管理的js库(不是react插件库可以用在其他js框架中例如vue,但是基本用在react中)
Redux是为javascript应用程序提供一个状态管理工具
集中的管理react中多个组件的状态
redux三大原则
单一数据源:整个应用的 state 被储存在一棵 object tree 中,并且这个 object tree 只存在于唯一一个 store
中
State 是只读的:唯一改变 state 的方法就是触发 action
,action 是一个用于描述已发生事件的普通对象。
使用纯函数来执行修改:为了描述 action 如何改变 state tree ,你需要编写reducer
(一些纯函数,它接收先前的 state
和action
)
基本使用
1.下载redux npm install --save redux
2.创建文件夹 store 在创建文件 index.js 用来容纳相关redux代码
3.开始创建store对象
// 1.引用redux 并且解构出 createStore方法来进行store对象
import {createStore} from "redux"
// 6创建数据
let data={
name:"xixi",
age:18
}
// 5创建一个纯函数里面包含数据与修改动作 7 把上面创建的数据用es6函数形参默认值的方式传递给state
let reducer=(state=data,action)=>{
return state
}
// 2.开始创建store对象 4.给store传入数据与修改动作reducer
let store=createStore(reducer)
// 3.暴露store对象
export default store
4.测试一下看看创建的对不对
在src下的index.js全局配置文件中测试
// 测试下store配置是否正确
import store from "./store/index.js"
//getState()是获取数据
console.log(store.getState().name);
5.在组件中使用
import React, { Component } from 'react'
// 1.引用
import store from "../store/index.js"
export default class home extends Component {
constructor(props){
super(props)
this.state={
// 从store中获取并且赋值给state
storeText:store.getState().name
}
}
render() {
return (
<div>
home----{this.state.storeText}
</div>
)
}
}
修改
1.通过dispatch调用修改操作
add=()=>{
// 通过dispatch()来调用触发修改
store.dispatch({type:"ADD_LIST_NUM"})//type是修改的动作名
}
del=()=>{
store.dispatch({type:"DEL_LIST_NUM"})
}
2.开始创建这些修改的动作
import {createStore} from "redux"
let data={
name:"xixi",
age:18
}
let reducer=(state=data,action)=>{
switch (action.type) {//判断任务名 从而执行各种修改操作
case "ADD_LIST_NUM":
return {...state,age:state.age+1}
break;
case "DEL_LIST_NUM":
return {...state,age:state.age-1}
break;
default:
// 既没有添加页面删除那么就是读取初始化数据
return state
}
}
let store=createStore(reducer)
export default store
问题 大家都发现数据变了 但是页面的展示没有变 怎么办?
因为数据是在store里面变了 但是页面中并没有重新render所以页面不要更新
3.使用**subscribe()**来监听store中的数据变化—— 当数据改变就会触发执行setState 当调用setState
——render就会 重新渲染 那么页面就更新了
constructor(props){
super(props)
this.state={
// 从store中获取并且赋值给state
storeText:store.getState().age
}
}
//写在钩子函数里面
// 监听store的数据 当数据改变就会触发执行setState 当调用setState
// render就会 重新渲染 那么页面就更新了
componentDidMount() {
store.subscribe(()=>{
this.setState({
age:store.getState().age
})
})
}
参数传递
在使用dispatch的时候可以向redux中传递参数
store.dispatch({type:"ADD_LIST_NUM",num:10})//传递一个num的数据
在action中进行使用
let reducer=(state=data,action)=>{
switch (action.type) {
case "ADD_LIST_NUM":
return {...state,age:state.age+action.num}//使用数据
break;
case "DEL_LIST_NUM":
return {...state,age:state.age-1}
break;
default:
return state
}
}
redux封装
封装派发动作
今后会有很多个动作 那么我们就把这些派发动作放在一起 好管理
1.在store文件夹下创建一个文件名字随便起(actionCreator.js)
2.在当前文件中封装任务名
// 封装派发动作
export let up=()=>{
return {type:"UP_DATA"}
}
export let up=()=>{
return {type:"XXX"}
}
....很多个
3.在想使用这个派发动作的组件中引用使用
引用的时候 如果是 当前要使用多个模块中的东西要引很多次非常麻烦 所以我们可以使用
import * as 随便起个名字 from 引用文件路径 //来进行统一全部引用
fun(){
// 调用redux的修改
store.dispatch(ac.up()) //使用封装的任务
}
import React, { Component } from 'react'
import store from "../store/index.js"
import * as ac from "../store/actionCreator.js"//引用封装的任务
export default class home extends Component {
constructor(props){
super(props)
this.state={
age:store.getState().age
}
}
componentDidMount() {
store.subscribe(()=>{
this.setState({
age:store.getState().age
})
})
}
fun(){
// 调用redux的修改
store.dispatch(ac.up()) //使用封装的任务
}
render() {
return (
<div>
<h1>redux的基本操作--{this.state.age}</h1>
<button onClick={this.fun.bind(this)}>点我修改</button>
</div>
)
}
}
我们也可以给redux中传递payload
在封装动作的时候也可以给当前函数添加形参来接收传递的数据
export let up=(text)=>{
return {type:"UP_DATA",text}
}
switch (action.type) {
case "ADD":
return {...state,age:action.text}
break;
//在这里调用其中一个ac.xx
store.dispatch(ac.up("wedrfgxcvb"))
//就可以传递自己想要的参数
封装派发动作名
方便后期统一进行名字的修改
1.在store下创建actionType.js
2.在其中进行名字的封装
export const UP_DATA="UP_DATA"
// let typename="WL"
// let obj={
// UP_DATA:typename+"_DATA",//UP_DATA
// UP_DEL:typename+"_DEL"//UP_DEL
// }
// export default obj
3.在调用的时候引用使用
reducer 模块封装于合并
-
新建一个module的文件夹用来存放单独组件的模块
-
把原来写在一起的reducer内容单独放到一个模块文件中
// 就是单独组件的数据与修改import * as at from "../actionTypes.js"let data={ name:"xixi", age:19}let homereducer=(state=data,action)=>{ switch (action.type) { case at.UP_DATA: return {...state,age:action.text} break; default: return state break; } }export default homereducer
3.创建一个reducer.js进行和并
// 我需要把所有的render模块在当前文件合并成一个// 1.引用所有你要合并的模块import homereducer from "./module/homem.js"import shopreducer from "./module/shopm.js"// 2.引用合并的工具方法 combineReducers合并模块import {combineReducers} from "redux"// 3.开始合并let reducer=combineReducers({ homem:homereducer, shopm:shopreducer})export default reducer
4.在store对象种引用这个合并的文件 并且传入最终合并成功的reducer
import {createStore} from "redux"import reducer from "./reducer.js"let store=createStore(reducer)export default store
5.因为使用了模块所以在使用数据的时候需要是 store.getState().模块名.数据
react-redux
react-redux是专门为reacr开发的状态管理工具
下载:cnpm install --save react-redux
使用:
1.设置provider 在全局配置文件中引用使用
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/reactreduxcom.jsx';
import reportWebVitals from './reportWebVitals';
// 1.引用react-redux 并且结构出Provider
import {Provider} from "react-redux"
// 2.引用store
import store from "./store/index.js"
ReactDOM.render(
// 3.把store传递给所有的子组件
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
2.在组件中引用connect用来关联当前组件与store
````
import React, { Component } from 'react'
// 1.引用连接的高阶组件
import {connect} from "react-redux"
class reactreduxcom extends Component {
render() {
return (
<div>
<h1>react-redux的使用</h1>
</div>
)
}
}
// 因为connect是一个方法 当这个方法被调用之后才是一个高阶组件HOC
export default connect()(reactreduxcom)
3.把redux的数据传递给组件来接收
export default connect(state=>({state}))(reactreduxcom)
4.读取 this.props.state.模块名.xxxx
<h1>react-redux的使用---{this.props.state.homem.name}</h1>
5.修改
fun=()=>{
this.props.dispatch(updata("我是使用react-redux修改的"))
}
axios 使用
与vue相同
跨域
要解决跨域 使用正向代理
1.找到/node_modules/react-scripts/config/webpackDevServer.config.js 当前文件
2.在文件中找到proxy 使用下面代码替换
proxy:{
"/api(可以随便写)":{
target:"请求地址",
changeOrigin:true,
"pathRewrite":{
"^/api(和上面一样)":"/"
}
}
},
3.修改请求为/api
4.重启项目
弹射
刚才在解决跨域的时候配置文件隐藏过深非常麻烦。
使用弹射(把配置文件设置根目录中来)eject
注意注意注意:去公司请不要随便弹射(出问题概不负责)
eject 操作是不可逆的,执行之后会把所有细节都暴露在我们面前,让项目目录变得很庞大。所以不要一上项目就弹射
使用: npm run eject
fetch VS ajax VS axios
传统 Ajax 指的是 XMLHttpRequest(XHR), 最早出现的发送后端请求技术,隶属于原始js中,核心使用XMLHttpRequest对象,多个请求之间如果有先后关系的话,就会出现回调地狱。JQuery ajax 是对原生XHR的封装
axios 是一个基于Promise ,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范,
fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。