文章目录
React的基础知识
-
基本使用
react需要依赖react和react-dom这两个包
安装:npm install react react-dom@版本号 1.创建虚拟dom ...参数 1.元素名称 2.元素属性 3.元素的子节点 React.createElement('h1',{class ="add":属性节点}子节点) //但是这个js写法对于多级的html结构很不友好,需要多次套娃 2.渲染创建好的虚拟dom到页面中(web应用) ...参数 1.要渲染的虚拟dom元素 2.挂载点 ReactDOM.render(虚拟dom元素,在页面中挂载的地方)
-
React脚手架
安装:npm install -g create-react-app //全局安装React脚手架 验证是否安装完成 :create-react-app -V出现对应的版本号即是安装完成 初始化项目: npm create-react-app 项目名 启动项目: npm start
-
JSX的应用
在上述的步骤已经可以简单的搭建出一个web应用
用react的createElement方法创建元素
用渲染器将元素渲染到指定的节点下面
但是如果一个很复杂的html页面的元素用react创建的话就显得有点繁琐,所以引入JSX
1.简介:
JSX是JavaScript XML的简介表示在JavaScript中书写XML,XML和HTML又有着密不可分的联系,所以JSX看着很像HTML,让人看着直观简洁
Jsx简单语法规则 |
---|
1.定义虚拟dom的时候,不要写引号 |
2.在jsx中引入JavaScript时要用{} |
3.样式的类名不用用class,要用className |
4.内联样式,要用js对象的方式写在jsx中,而jsx要用{},所以行内样式为{{key:v}} |
5.只能有一个根标签 |
6.标签必须闭合 |
7.自定义标签的时候,首字母小写的话会将标签转为html同名的元素,没有的话会报错,如果首字母大写,React会找相应的组件 |
jsx创建元素
const jsx = <p>内容</p>
渲染
ReactDOM.render(jsx,要挂载的元素)
2.数据驱动视图
如果想在react中插入JavaScript的数据用 { }
const name = '傻逼'
const jsx = (
<h1>
hello,{name}/*这里都可以插入合法的js表达式*/
</h1>
)
ps:jsx自己也是一个js表达式
js对象是一个例外,一般只会出现在style属性中
不能出现语句if ,for等
3.条件渲染or列表渲染
条件渲染:用函数返回jsx的方式,函数内部通过if或者其他语句判断具体返回
列表渲染:用数组的map方法
在jsx之中,会自动遍历数组将之呈现到页面之上
如 let data = ['昨天',‘明天’,‘后天’] const jsx = (
<h1>{data}<h1>
)
会呈现出<h1>昨天明天后天</h1>同效果真实dom,所以如果遍历数组返回的还是带有数组的jsx就可以实现列表渲染
const jsx = (
<h1>{data.map((item)=>{
return <span key=xxx>{item}<span/>
})}</h1>
)
注意:渲染的时候应该添加key属性,key的值要保持唯一,尽量避免使用索引号作为key
4.样式处理两种方法
1.使用style={样式对象:遵循驼峰命名}: 如style = {{color:"red",backgroundColor:'blue'}}
2.类名(在react中一般不使用class应为是关键字,用className代替)
<h1 className = "style">样式的处理</h1>
react组件基本使用
-
函数组件:适用于简单组件
定义一个简单的函数组件 function Vc() { return jsx如<h1>你好</h1> } ...箭头函数 const Hi = ()=><h1>你好</h1> 渲染组件到页面之上 ReactDOM.render(<Vc/>:要渲染的组件,document.getElementById("root"):挂载点) 注意:函数组件必须有返回值 组件名字必须大写,React据此区分 组件 和 普通的React元素的区别 使用函数名字作为组件的标签名 不想渲染任何内容就返回null
-
类组件:适用于复杂组件
...类组件
1. class Hi extends React.Component{
this:是Hi类组件的实例对象
render(){ return <div>类组件</div> }
}
2.渲染到页面之上 ReactDoM.render(<Hi/>,documnet.getElementById("root"))
在这一步React帮你调用了Hi构造函数new出一个实例对象,用该对象调用render方法拿到返回值,转化为真实dom渲染到页面之上
注意:类组件必须以大写字母开头
类组件应该继承React.Component父类,从而可以使用父类中提供的方法
类组件必须提供render方法,而且必须有返回值,不想渲染返回null
组件的三大属性
组件实例的state和有状态和无状态(有数据和无数据)
理解:组件又被叫做“状态机”,通过更新组件的state来更新对应页面的显示
- 函数组件又叫做无状态组件,类组件又叫做有状态组件
函数没有实例对象,而类组件可以由React自动调用实例一个对象,而每一个对象也可以说是组件实例上面
就可以有自己独有的数据或者说是状态 - 状态就是数据
- 函数组件只负责数据展示,静态的无互动性的
- 类组件可以实现响应式
状态就是数据
class Hi extends React.Component {
constructot{
super()
this.state = {
数据:值
}
handle(){
log:this
this.setState({数据:变化})
}
}
//两种方式二选一,下面是简化的方式
state = {
数据:值
}
render(){
return(
<div>取出数据状态{this.state.数据}</div>
<button Onlick={}></button>//绑定时候应为要访问js表达式要加{}
)
}
}
数据的更新、
-
组件的事件
React事件绑定语法用on+事件名称如 onClick 采用驼峰命名法 ;事件对象,和原生的差不多(合成事件)
绑定事件
function App(){
function handle(){
log:函数组件的事件绑定
}
return <div onClick={handle}>事件绑定</div>
}
class App extends React.Component{
handle(){
}
render(){
return <div onClick={this.handle}></div>
/***handle作为onclick的回调,不是通过实例调用的而是直接调用,而在类中的函数默认开启局部严格模式,所以函数里面的this是undefined*/
}
}
-
this指向问题
- 在上诉代码中如果直接在button中绑定事件像```react <button Onlick={this.handle}></button>,当调用的时候,会报错,因为调用时候this并不是指向该组件,而是指向外面的全局对象undefined ```
解决方法:想办法将函数里面的this指向组件
1.箭头函数
<button onClick={()=>this.handle()}>this指向问题</button> //在该作用域中箭头函数里面的this指向上一个作用域就是组件环境,所以handle函数就指向组件
2.bind改变指向
constructor(){ super() this.handle/**这个函数是在实例上面定义的**/ = this.handle/**这个函数是当初类定义的时候的函数,在实例的原型对象上面**/.bind(this) } //就是在构造函数中修改,因为构造函数会第一执行 但是本菜感觉不好,因为违背了面向对象的构造函数最初的意愿,每次创建都会执行一遍
3.定义的时候用箭头函数
handle = () =>{ this.setState({}) }
-
数据的修改
在class类组件之中,state里面的数据不能直接修改,会造成页面无响应的结果
- 数据更新的意义在于重新渲染页面,所以 想要重新渲染页面并且想直接修改数据以下代码可以实现但是不推荐
function b() { console.log("重新渲染了"); ReactDOM.render(<Weather></Weather>, document.getElementById('test')) } class Weather extends React.Component { constructor() { super() this.state = { isHot: true } } demo = ()=>{ // 'use strict' this.state.isHot=!this.state.isHot; console.log(this.state.isHot); b() } render() { const { isHot } = this.state return <h1 onClick={this.demo}>{isHot?"热":"冷"}</h1> } } ReactDOM.render(<Weather></Weather>, document.getElementById('test'))
-
通过setState内置函数来修改
demo()=>{this.setState({isHot:!isHot})}
- 简写
- class Weather extends React.Component {
state = {
isHot: true
}
demo = ()=>{
// ‘use strict’
}
render() {
const { isHot } = this.state
return < h1 onClick={this.demo}>{isHot?“热”:“冷”}< /h1>
}
}
组件实例的props
- 简单使用
在每一个类组件实例上面都有一个props属性,而在渲染组件的时候在组件标签中传入标签属性的时候会自动传递给props
render() {
const { isHot } = this.state
return <h1 onClick={this.demo}>{this.props.name}{isHot?"热":"冷"}</h1>
}
--------
ReactDOM.render(<Weather name="张三" age=18></Weather>, document.getElementById('test'))
- 批量传递
const weather = {name:"阴天",age:2018}
ReactDOM.render(<Weather {...weather}></Weather>, document.getElementById('test'))
- 对props进行限制
限制是针对的传过来的数据的类型进行限制,
第一种方式
:React v15.5 开始已弃用
Person.propTypes = {
name:React.PropTypes.string.isRequired,
age:React.PropTypes.number
}
第二种方式
:
Person.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number.
speck:PropTypes.func
}
上述也可以用static将之放在class类组件定义里面
默认值
Person.defaultProps = {
age: 18,
sex:‘男’
speck:PropTypes.func
}
组件的实例属性refs
- 字符串形式的ref:不推荐后续可能弃用
< input ref="input1"/>
- 回调形式的ref
<input ref={(c)=>{this.input1 = c}}
- createRef创建ref容器· ps:是一个函数调用后可以返回一个容器,该容器可以存储被ref所标识的节点
myRef = React.createRef()
< input ref={this.myRef}/>
受控组件
在 HTML 中,表单元素(如、 和 )通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。
我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。ps:通常通过onchange事件,类似于vue的双向数据绑定
---------简单的受控组件
class Login extends React.Component{
state={
username:"",
password:""
}
login=()=>{
// alert(`账号是${this.inputUsername.value}密码是${this.inputPassword.value}`)
console.log(this);
alert(`账号是${this.state.username},密码是${this.state.password}`)
}
CollectForm=(formDtype)=>{
return (event)=>{
this.setState({[formDtype]:event.target.value})
}
}
render() {
return <div>
账号<input onChange={this.CollectForm("username")} type="text" placehodler="请输入账号"/>
密码<input onChange={this.CollectForm("password")} type="text" placehodler="请输入密码" /><br/>
<button onClick={this.login}>登录</button>
</div>
}
}
ps:函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数之后统一处理的函数 编码方式
生命周期钩子旧版本
1. 初始化阶段: 由ReactDOM.render()触发—初次渲染
-
constructor()
-
componentWillMount()
-
render()
-
componentDidMount()
2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
0.componentWillReceiveProps注意子组件第一次收到自定义属性的时候不会调用,属性更新的时候才会调用
-
shouldComponentUpdate()
-
componentWillUpdate()
-
render()
-
componentDidUpdate()
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount()
生命周期新版本
react配置代理
react脚手架配置代理总结
方法一
在package.json中追加如下配置
"proxy":"http://localhost:5000"
说明:
- 优点:配置简单,前端请求资源时可以不加任何前缀。
- 缺点:不能配置多个代理。
- 工作方式:上述方式配置代理,当请求了3000不存在的资源时,那么该请求会转发给5000 (优先匹配前端资源)
方法二
-
第一步:创建代理配置文件
在src下创建配置文件:src/setupProxy.js
-
编写setupProxy.js配置具体代理规则:
const proxy = require('http-proxy-middleware') module.exports = function(app) { app.use( proxy('/api1', { //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000) target: 'http://localhost:5000', //配置转发目标地址(能返回数据的服务器地址) changeOrigin: true, //控制服务器接收到的请求头中host字段的值 /* changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000 changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000 changeOrigin默认值为false,但我们一般将changeOrigin值设为true */ pathRewrite: {'^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置) }), proxy('/api2', { target: 'http://localhost:5001', changeOrigin: true, pathRewrite: {'^/api2': ''} }) ) }
说明:
- 优点:可以配置多个代理,可以灵活的控制请求是否走代理。
- 缺点:配置繁琐,前端请求资源时必须加前缀。