什么是react
react起源于facebook团队,官网, react是基于V层, 需要周边环境的支持;
react是基于jsx语法, js+xml , 在模板里写js , 属于虚拟dom开发
react特点:
- 组件式开发, 为了代码的封装复用
- 虚拟dom开发
- 虚拟dom diff算法, 把虚拟dom转化成真实dom
- react社区完善, 可以开发大型的应用
课程中我们讲的最新的react版本 v18版本
react开发需要依赖2个包
react : 因为 react官网推出混合app(react-native), 所以把react分离成了2个方向, 第一个方向是web(react-dom), 第二个方向是app(react-native)
web和app的共同的核心部分还是保留在react包
开发react web端需要引入: react react-dom
开发react app 端需要引入: react react-native
app应用程序
-
原生app : 就是安卓和ios端,开发成本比较高,性能是最好的
-
webapp: 就是 h5页面, 通webview浏览器嵌套下, 性能是最差的
-
混合app: uniapp是多端开发, 可以小程序, 也可以开发混合app,react-native也可以开发混合app
什么是虚拟dom
虚拟dom是一种用javascript对象表示内存中的抽象的dom树,是对真实dom的一个轻量映射, 作用是在前端框架中提供一种高效的dom操作更新机制,可以优化性能和提升用户的体验。
虚拟dom就是一个js对象, 至少包括标签tag,属性attrs,内容children属性
1.React.createElement创建虚拟dom
回顾下 es5创建真实dom的方式
var dom = document.createElement('div');
dom.id = 'app'
dom.className ='hello'
dom.innerHTML = '我来了'
document.body.appendChild(dom)
使用react.createElement创建虚拟dom
<!-- <div id="app" class="heelo">我来了</div> -->
<div id="app"></div>
<script>
// es5的方式创建真实dom节点,并插入到body中 复习下
/* var dom = document.createElement('div');
dom.id = 'app'
dom.className ='hello'
dom.innerHTML = '我来了'
document.body.appendChild(dom) */
// 3个参数:
// 1. tag标签
// 2.虚拟dom的一些属性
// 3. 内容
// React: 来自react.development.js核心包的api
var xDom = React.createElement('div',{
className:'apple',
style:{color:'red'}
},'hello react');
// 虚拟dom 如何渲染在页面中
// ReactDOM: 来自react-dom.development.js的api
let root = ReactDOM.createRoot(document.getElementById('app'));
// 使用ReactDOM.createRoot创建根节点
root.render(xDom);
// 通过render 方法把虚拟dom转化成真实dom渲染在模板中
2.使用jsx创建虚拟dom
babel包一般用来把es6,es7语法转化成浏览器可以识别的es5语言,同时babel也内置了对jsx语法的支持
jsx = javascript (js) + XML(html) ,可以在模板中写js语言
jsx的特点:
1.开发代码更简洁
2.性能上更好, 执行代码的速度更快
需要引入babel包
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<div id="app"></div>
<!-- text/babel 用来支持jsx的语法 -->
<script type="text/babel">
var str = 'hello react';
// background-color
var vDOM = <div className='hello' style={{color:'red',backgroundColor:'blue'}}> {str}</div>;
let root = ReactDOM.createRoot(document.getElementById('app'));
root.render(vDOM)
</script>
注意点:
1.需要依赖babel包,在script上条件type="text/babel"
2.react,jsx中使用模板渲染标志是{}
3.style样式本来是有多个属性的, 是以对象的对象的形式赋值, style标签外层的{}是react的语法,第二个{}是style对象形式
4.style中的样式,如果是烤串 式 background-color 统一写成 小驼峰 backgroundColor
5.使用外部样式class,jsx中统一使用className
jsx逻辑运算处理
加,减,乘,除 ,||, && , 三目元算符
react中没有指令, 需要通过逻辑运算去控制节点的显示和隐藏等操作
var num1 = 1;
var num2 = 3;
var str1 = '';
var isBool = false;
var vDOM = <div>
演示:
<p> {num1+num2} </p>
<p>{num2-num1}</p>
<p> {num1 *num2 }</p>
<p> {num2 / num1 }</p>
<p> {str1 || '临时的内容'}</p>
<p>
{isBool && <div className="demo">我们在学react</div>}
</p>
<p> {isBool ? '苹果' :'香蕉' } </p>
<p> {JSON.stringify(isBool)} </p>
</div>;
let root = ReactDOM.createRoot(document.getElementById('app'));
root.render(vDOM)
boolean值 不能直接在模板渲染, 如果你想打印boolean值来测试, 可以使用{JSON.stringify(isBool) }
jsx数据动态渲染
实践需求:
var names = ['苹果','香蕉','桃子'];
利用jsx的语法把数组names 解析成列表进行渲染
列表结构
<ul><li>香蕉</li></ul>
总结:
1.jsx中不能直接渲染对象,但是可以直接渲染数组
2.如果需要把数组中的数据渲染在模板, 需要通过map循环,处理成我们想要的结构,然后在模板中渲染
3.map循环的时候, 返回的虚拟dom标签必须有一个唯一的key, 提高页面的性能
<div id="app"></div>
<script type="text/babel">
// var names = ['苹果','香蕉','桃子'];
var names = [{name:'苹果',price:20},{name:'香蕉',price:10},{name:'桃子',price:50}];
var obj = {name:'alice'};
var list = names.map((item,index)=>{
return <li key={index}>{item.name} --- {item.price }</li>
})
var vDOM = <div>
hello
<ul>
{list}
</ul>
</div>;
var root = ReactDOM.createRoot(document.getElementById('app'));
root.render(vDOM);
组件的概念
react和vue一样, 都是组件式开发,组件式开发是为了提高开发效率和提高组件的可复用性, 方便后期维护和扩展等;
react中定义组件有2种方式:
react版本v16.8之前, 一般都使用类组件, 比较强大, 但是官网比较推荐使用函数组件
1.类组件: class
2.函数式组件: function
1.复习class类
<script>
class People {
static school = '蜗牛';
constructor(name,age){
// 实例属性
this.username = name;
this.age = age;
}
sayHello(){
console.log(this);
// this People类的实例化对象
console.log('hello,你好');
}
singFun=()=>{
console.log('==========');
console.log(this);
console.log('唱歌');
}
}
var p1 = new People('xiaohong',20) ;
// 每次实例化一个对象,都是需要先走constructor
// 访问静态属性直接通过类
console.log(People.school);
// p1.sayHello();
// p1.sing();
var sayTest = p1.sayHello;
sayTest()
var singTest = p1.singFun;
singTest()
总结:
1.类的名字首字母大写
2.类中的静态属性和静态方法使用关键字static 定义,可以直接通 类名.静态属性 访问
3.在类中定义方法的, 一般情况下指向类的实例化对象
4.类中定义的普通方法可以改变this的指向, 但是类中的箭头函数永远指向类的实例化对象
类中普通方法 通过实例化对象得到后赋值给其他变量后, this为什么变成undefined
- 赋值方法后,是依赖上下文环境的,正常情况下是指向window对象, 但是class类中自动开启了严格模式, 所以是undefined
2.在类中定义普通函数和箭头函数的区别
1.类中定义的箭头函数,没有挂载在类组件的原型上, 在类继承中, 箭头函数也被继承,但不是被挂载在原型上
2.一般情况下类中的this指向实例,类中方法实例调用的话,类方法中this就指向实例对象
3.在JavaScript中,类中的普通方法被存储在类的原型对象中。当你将一个方法复制给一个变量后再执行,方法中的this可以改变。这是因为this在JavaScript中是动态绑定的,它的值取决于函数被调用的上下文。
3.但是把类中的方法,赋值给变量之后再调用就相当于自调用了,就不是实例调用了。赋值方法this就是指向window,但是类中的方法是自动开启局部严格模式了,所以赋值方法this最终是undefined
this会根据是否是严格模式而指向undefined或者全局环境。
注:ES6 的class内部默认为严格模式
4.类中的普通函数可以通过bind, call, apply改变函数的this指向, 箭头函数不能通过bind, call,apply改变他的this指向,类中的箭头函数this 一直都是指向类的实例化对象的
3.继承
使用关键字extends实现继承, 必须在constructor有一个super方法
class Teacher extends People {
constructor(name,age,country){
super(name,age);
this.country = country;
}
teach(){
console.log('老师教书');
}
}
var tea1 = new Teacher('王老师','30','中国');
tea1.teach();
实现继承的时候, constructor是必须的, 但是如果不写,es6的语法会自动帮你添加,
那如果类有变量需要传去, 可以不省略constructor, 如果没有变量, 建议使用省略constructor的形式去写
简写的形式
class Teacher extends People {
student = '小王'
teach(){
console.log('老师教书');
console.log(this.student);
}
}
4.类中定义计算器属性
get fullname(){
return this.username + ' ' + this.lastname;
}
在实例化对象中直接访问 , 计算器属性中, 只有依赖的数据发生了改变, 计算器属性的值会重新计算
react中定义类组件
// 创建一个Header类组件
class Header extends React.Component {
// constructor(){
// super();
// this.username = 'xiaohua'
// }
// 简写的形式
username = 'xiaohua'
render(){
return <div> 我是header组件 {this.username} </div>
}
}
var root = ReactDOM.createRoot(document.getElementById('app'));
root.render(<Header />)
总结:
1.类组件的首字母大写
2.类组件中必须有一个render方法,比例必须有一个return 返回虚拟dom
3.而且return的虚拟dom必须有一个根节点
定类组件中的内部数据
通过this.sate = 组件内部数据
constructor(){
super();
// this.username = 'xiaohua'
// 组件内部数据
this.state = {
username:'xiaohua',
age:20
}
}
简写的形式, 直接在类组件中定义state
state = {
username:'xiaohua',
age:20
}
在模板中访问类组件中的数据
this.state.username
修改类组件中数据使用setState
setState是一个异步函数, 只要执行了setState, 就会再次调用render函数,引发模板的重新渲染
方式一:
this.setState({
username:'小刚'
})
方式二:
setState 可以接收2个参数,
第一个函数,修改数据后, 通过return返回
第二个回调 可以获取修改后的最新值
this.setState((prev)=>{
// console.log(prev); // 组件内部数据
return {
username:'小刚'
}
},()=>{
console.log(this.state.username);
})
事件绑定使用onClick
<button onClick={this.updateName}>修改name</button>
注意: onClick后 必须跟着一个函数, 为了一劳永逸的解决函数this指向的问题, 我们建议大家使用箭头函数定义
事件绑定传参方式
方式一: data-烤串的形式传参
<button data-username='小刚' onClick={this.updateName}>修改name</button>
获取参数, 通过ev事件对象获取
updateName = (ev)=>{
console.log(ev.currentTarget.dataset.username);
}
方式二:使用箭头函数的方式传参
<button onClick={()=>this.updateName('小红')}>修改name</button>
获取参数
updateName = (name)=>{
this.setState({
username:name
})
}
推荐第二种箭头函数方式传参
类组件中props传值
使用props传值
<Header title="蜗牛" bg="red" />
类组件中获取props, 在constructor中使用props接收
constructor(props){
// 组件内部数据
super(props);
console.log(this.props);
this.state = {
username:'xiaohua',
age:20
}
}
或者使用简写的方式, 直接不用写 , 直接在模板中通过 {this.props.属性名} 获取
补充:
<Header title="蜗牛" bg="red" height="80px" />
render(){
const {title,bg,height} = this.props;
return <div style={{backgroundColor:bg, height:height}}>
<p>
props中的数据 <br/>
{this.props.title}
</p>
</div>
}
定义默认属性: 直接关键字static defaultProps定义, 以对象的形式, 可以定义多个默认属性
static defaultProps = {
height:'100px',
bg:'blue'
}
- 在模板渲染中, 建议大家使用解构方式 拿到state中数据 , 或者props中的数据,再进行数据的渲染
搭建react环境
使用官方create-react-app, 基于webpack的
npx create-react-app 项目名称
总结:
- npx这个命令无需安装, 直接使用,node安装后, 自动就有了
- npx安装的目的是每次创建项目都使用最新的 create-react-app的版本,并不需要在本地安装这个create-react-app
下载插件:
在实际开发过程中,由于这些组件和函数组件它的结构都是固定的,所以可以使用一些插件将其生成出来
使用rcc生成类组件,使用rfc生成函数组件
项目目录结构
src:存放开发的资源
---components:代表组件
---pages/views:代表页面(一般跟路由相关的页面)
---utils:存放工具
index.js:代表项目入口文件,启动项目首先加载这个文件
App.js这个文件代表项目根组件。默认在Index.js被加载
React中组件有两种后缀:以js结尾的文件,jsx结尾文件(推荐)
yarn包管理工具
yarn包管理管局,类似npm, 出自facebook团队
可以缓存你已经下载过的包,哪怕是在离线的情况下, 也可以下载你之前下载过的包
1: 快速 , 因为从缓存直接读取
2 :安全 ,可靠
参考官方文档yarn.bootcss.com/
yarn的安装
npm install yarn -g
查看yarn的版本号
yarn -v // 或者 yarn --version
初始化 一个包文件package.json
yarn init -y
通过yarn安装包
yarn add 包的名字 // 默认安装最新的包
yarn add 包的名字@2 //是定版本安装
不管你用npm 还是yarn ,如果不指定版本号, 安装都是最新的版本
删除你安装的包
yarn remove 包的名字
全局安装某一个包
yarn global add 包的名字
全局删除某一个包
yarn global remove 包的名字
设置镜像
yarn config set registry http://registry.npm.taobao.org
yarn config set sass_binary_site http://cdn.npm.taobao.org/dist/node-sass
整体安装package.json里的包
yarn 或者 yarn install
检查环境变量配置
右键电脑 - 》 属性-》点击高级系统设置-》点击环境变量-》点击系统变量的path,然后进行配置
nvm切换node版本号
nvm 默认安装在c盘, 不要选其他的盘
走入企业后 , 第一件时间是和你同事核对项目node的版本号, node -v, 至少大版本好要保持一致, 然后在安装项目的依赖包
如果你同时开发多个项目, 2个项目是依赖不同的node版本号
A项目: node版本18
B项目: node版本16
比较简便的方式通过nvm管理node版本号
如果有项目使用不同的node, 可以使用nvm来切换node版本号
nvm -v // 查看nvm版本号
nvm install 18.16.0 // node的版本号要确保存在的
nvm ls // 查看本地安装的所有node版本
nvm use 18.16.0 //使用某一个node版本
node -v // 查看当前使用的node版本
安装scss预处理
create-react-app安装的项目 ,已经内置了scss的配置, 你不需要配置,只需要安装node-sass sass-loader, 如果你要配置less,就会稍微麻烦点, 因为create-react-app没有内置less的配置,所以这里选择scss
yarn add node-sass sass-loader -D //安装在开发包
node-sass安装不上可以这样安装
npm install sass node-sass@npm:sass
create-react-app创建的项目, 已经内置babel的配置, 所以我们新建项目的时候, 可以直接使用jsx