vue和react作为当下前端最主流的两大框架,当然需要学习啦!
还没有学过vue的可以去我之前的博客vue入门系列!!
一、介绍React
1.1、简介
- React 是一个用于构建用户界面的 JAVASCRIPT 库。
- React主要用于构建UI。
- React 起源于 Facebook 的内部项目,用来架设 Instagram 的网站,并于 2013 年 5 月开源。
- React 拥有较高的性能,代码逻辑非常简单。
1.2、特点
简单概述下:
1)高效 −React通过对DOM的模拟,最大限度地减少与DOM的交互。
2)灵活 −React可以与已知的库或框架很好地配合。
3) JSX − JSX 是 JavaScript 语法的扩展。
4) 组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。
单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,也正因此,它比传统数据绑定更简单。
1.3、与其他框架对比
angularJs | reactJs | vueJs | |
---|---|---|---|
控制器 | √ | - | - |
过滤器 | √ | - | √ |
指令 | √ | - | √ |
模板语法 | √ | - | √ |
服务 | √ | - | - |
组件 | - | √ | √ |
jsx | - | √ | 2.0之后加入 |
相同点是:都采用虚拟dom,和数据驱动
二、搭建环境
2.1、通过引入文件的方式
<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">
//第一个react程序
ReactDOM.render(
<p>第一个react程序</p>,
document.getElementsByClassName('box')[0]
)
</script>
引入的三个js文件:
-
1、React.js:
React的核心库,解析组件,识别jsx
https://cdn.staticfile.org/react/16.4.0/umd/react.development.js -
2、reactDom.js:
处理与dom相关的操作
https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js
-
3、Babel.js
Babel 可以将 ES6 代码转为 ES5 代码,这样我们就能在目前不支持 ES6 浏览器上执行 React 代码。Babel 内嵌了对 JSX 的支持。通过将 Babel 和 babel-sublime 包(package)一同使用可以让源码的语法渲染上升到一个全新的水平
https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js
2.2、通过官方脚手架的方式
- 安装
create-react-app
npm install create-react-app -g
- 创建 react项目
create-react-app 目录 | npm init react-app 目录
npm start 开发
npm run build 打包
//调试 需要安装给chrome浏览器一个插件 react-dev-tools
环境解析
- react: 核心包,解析组件,识别jsx
- react-dom: 编译 -> 浏览器
- react-scrpts: react的项目环境配置
- manifest.json 生成一个网页的桌面快捷方式时,会以这个文件中的内容作为图标和文字的显示内容
- registerServiceWorker.js支持离线访问,所以用起来和原生app的体验很接近,只有打包生成线上版本的react项目时,registerServiceWorker.js才会有效。服务器必须采用https协议
- 对Internet Explorer 9,10和11的支持需要polyfill。
2.3、第三方脚手架
yeomen/dva/umi
三、JSX
首先,我们开始编写第一个react程序:(前面其实展示过)
<body>
<div class="box">
</div>
</body>
<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">
//第一个react程序
ReactDOM.render(
<p>第一个react程序</p>,
document.getElementsByClassName('box')[0]
)
</script>
注意:script标签的type取值为:text/babel
页面显示效果:
3.1、ReactDOM.render()函数
在程序中,我们可以看到通过 ReactDOM.render()
函数,将p标签渲染到了类名为box的标签中。
那么,ReactDOM.render()函数是什么??
ReactDOM.render 是 React 的最基本方法。用于将JSX写的模板(经过模板渲染(把javascript的结果替换单花括号里的内容))转为 HTML 语言,并渲染到指定的HTML标签里。
基本格式:
ReactDOM.render( JSX写的html模板,dom容器对象);
总结:一个react程序,就是把JSX通过 ReactDOM.render()
函数渲染到网页上。
那么,JSX是什么?
3.2、JSX介绍
JSX就是Javascript和XML结合的一种格式。是 JavaScript 的语法扩展,只要你把HTML代码写在JS里,那就是JSX。
3.3、JSX特点
1) JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。
2)它是类型安全的,在编译过程中就能发现错误。
3)使用 JSX 编写模板更加简单快速。
3.4、JSX的语法
所谓语法就是把html代码写在javascript中的要求规范。
3.4.1、XML基本语法
-
只能有一个根标签,外面加上圆括号。
-
标签要闭合(单标签要加斜杠)
<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">
ReactDOM.render(
//此处只有一个根标签div,否则会报错,如下图
<div>
<input type="button" value={msg2}/>{/*单标签必须以‘/’结尾*/}
</div>,
document.getElementsByClassName('box')[0]
)
</script>
3.4.2、元素类型
-
小写首字母对应 HTML的标签,组件名首字母大写。
-
注释使用 / * 内容 */ html标签内注释{/* 最外层有花括号*/}
<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">
ReactDOM.render(
<div>
<p>第一个react程序</p>{/*此处为注释*/}
</div>,
document.getElementsByClassName('box')[0]
)
</script>
3.4.3、元素属性
- 内联样式的style:样式名以驼峰命名法表示, 如font-size需写成fontSize。默认像素单位是 px(px不用写)
<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">
let sty = {backgroundColor:'red',
fontSize:24,
width:200,
height:100}
ReactDOM.render(
<div>
{/*此处style的值直接用单花括号,不用加引号*/}
<p style={sty}>第一个react程序</p>{/*样式style直接用单花括号*/}
</div>,
document.getElementsByClassName('box')[0]
)
</script>
- 外部样式的class:HTML中曾经的 class 属性改为 className(因为class是js的关键字),外部样式时使用
<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">
ReactDOM.render(
<div>
<div className="box2">{msg}</div>{/*类名class关键字用className代替*/}
</div>,
document.getElementsByClassName('box')[0]
)
</script>
- for 属性改为 htmlFor(因为for是js的关键字)。(for属性在html标签中是扩充单选框|复选框的选择范围)
- 事件名用驼峰命名法。HTML是全小写(onclick),JSX中是驼峰(onClick)
<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">
function add(){
msg2 = '我是按钮2'
console.log('msg2:',msg2);
}
ReactDOM.render(
<div>
{/*此处onclick写为onClick,驼峰命名法*/}
<p onClick={add}>点击我改变按钮的值</p>{/*事件名驼峰命名法*/}
</div>,
document.getElementsByClassName('box')[0]
)
</script>
3.4.4、javascript表达式
- 使用单花括号
react里没有vue中的指令,任何地方需要javascript的变量,表达式等等,只需要套上 单花括号就行
const element = <h1>Hello, {120+130}!</h1>
const element = <h1>Hello, {getName("张三疯")}!</h1>
注意:单花括号里只能写表达式,不能写语句(如:if,for)
四、条件渲染
就是普通的js条件判断语句。
<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">
let num = 23;
if(num>=18){
var htmlStr = <p>我成年了</p>
}else{
var htmlStr = <p>我是未成年</p>
}
ReactDOM.render(
<div>
{htmlStr}
</div>,
document.getElementById('box')
)
</script>
五、列表渲染
5.1、渲染数组
//数组里存放jsx
var arr=[
<li>张三疯</li>,
<li>张四疯</li>,
<li>张五疯</li>
]
const show = ()=> (
<ul>{arr}</ul>
)
ReactDOM.render(show(),document.getElementById("box"));
5.2、map()或者普通for循环
let arr = [
'平凡的世界',
'麦田里的守望者',
'最后一滴眼泪',
'活着'
]
ReactDOM.render(
<div>
{arr.map(item=>(<p>书名:《{item}》</p>))}
</div>,
document.getElementById('box')
)
六、组件
react中定义组件有三种写法:函数方式,ES5的写法(很少用了),ES6(类)的写法
6.1、函数组件
函数的返回值是JSX就行。即:如果一个函数的返回值是JSX,那么就可以当标签的方式使用。
//函数组件
function Vid(){
return <p>
我是函数组件
</p>
}
ReactDOM.render(
<div>
{Vid()}//通过调用函数使用
<Vid></Vid>//直接作为标签使用
</div>
,
document.getElementById('box')
)
6.2、类组件
定义一个类,继承自 React.Component,在该类里,必须有个render()函数,render函数返回一个JSX代码。
换句话说:一个普通的ES6的类,只要有一个render()函数,并且render()函数返回一个JSX,那么就是组件。
//类组件
class Vid extends React.Component{
render(){
return <p>我是类组件</p>
}
}
ReactDOM.render(
<div>
<Vid></Vid>//直接作为标签使用
{(new Vid()).render()}//实例对象并调用render方法使用
</div>
,
document.getElementById('box')
)
6.3、ES5的写法(React16后,已经废弃)
React.CreateClass()函数
var MyCom = React.createClass({
render:function(){ //vue中也有render函数,是完成模板的代码
return (
<div>
<h1>Hello, world!</h1>
</div>
);
}
});
6.4、多组件
// 标题
function MyTitle(){
return (
<h1>商品列表</h1>
)
}
// 详情
function MyDetail(){
return (
<ul>
<li>铅笔</li>
<li>钢笔</li>
</ul>
)
}
ReactDOM.render(
<div>
<MyTitle/>
<MyDetail/>
</div>,
document.getElementById('box')
);
七、props
props 是组件对外的接口。接收外部传入的数据。是组件的属性(等同于html标签的属性)。
注意:Props对于使用它的组件内部来说,是只读的。一旦赋值不能修改。
7.1、外部传值
<组件名 属性名1=值1 属性名2=值2 .. />
ReactDOM.render(
<div>
<Vid msg="我是传过去的props" data="附加信息"></Vid>
</div>
,
document.getElementById('box')
)
7.2、组件内部使用
7.2.1、函数组件内部使用
{props.属性名}
//函数组件
function Vid(props){
// let msg = '我是函数组件plus'
console.log(props);
return <div>
<p>{props.msg}</p>
<p>{props.data}</p>
</div>
}
7.2.2、类组件内部使用
{this.props.属性名}
//类组件
class Vid extends React.Component{
constructor(props){
super()
this.props = props
// console.log('this.props:',this.props);
console.log('this.props:',this.props);
}
render=()=>{
//此处要箭头函数,因为内部this指向改变了
return (<div>
<p>姓名:{this.props.name}</p>
</div>)
}
}
此处注意:
在类的constructor里直接打印props是undefined
若要获得传入的参数,需要加一句
this.props = props(props为构造函数的形参)
7.2.3、props传入对象
如果传递数据多的话,可以使用对象,但是必须使用扩展运算符(…)
- 传对象
let obj = {
name:'华为手机',
price:'4800元',
color:'深空蓝',
}
ReactDOM.render(
<div>
<Vid {...obj}></Vid>
</div>
,
document.getElementById('box')
)
- 组件内部使用
//类组件
class Vid extends React.Component{
constructor(props){
super()
this.props = props
// console.log('this.props:',this.props);
console.log('this.props:',this.props);
}
render=()=>{
//此处要箭头函数,因为内部this指向改变了
return (<div>
<p>名字:{this.props.name}</p>
<p>价格:{this.props.price}</p>
<p>颜色:{this.props.color}</p>
</div>)
}
}
7.2.4、props的默认值
1)、用 ||
function MyPerson(props){
//当没有传sex时值为女
let sex1 = props.sex || "女";
return (
<div>
<p>性别:{sex1}</p>
</div>
)
}
2)、defaultProps
格式:
//1)、函数式组件和类组件都可以:
组件名.defaultProps={
属性名: 默认值
}
//2)、若为类组件,可以在类的内部使用static修饰。
static defaultProps={
属性名: 默认值
}
函数组件使用defaultProps:
function Vid(props){
return <div>
她叫{props.name},今年{props.age}岁
</div>
}
Vid.defaultProps = {
name:'晓晓',
age:'23'
}
ReactDOM.render(
<div>
<Vid age="18"></Vid>
</div>
,
document.getElementById('box')
)
效果图:
7.2.5、类型检查
注意:react15.5后,React.propTypes已经移入到另外一个库里,请使用prop-types。
//类型约定:
组件名.propTypes={
属性名1:PropTypes.类型名,
属性名2:PropTypes.类型名
}
//必传参数
propName: PropsTypes.类型名.isRequired
类型名的可以取值为:
PropTypes.array,
PropTypes.bool,
PropTypes.func,
PropTypes.number,
PropTypes.object,
PropTypes.string,
PropTypes.symbol,
function MyPerson(props){
return (
<div>
<p>年龄:{props.age}</p>
</div>
)
}
MyPerson.propTypes={
//注意大小写
age:PropTypes.number.isRequired
}
ReactDOM.render(
<MyPerson age={12} />,
document.getElementById('box')
);
八、state状态机
state 是状态,状态就是数据,state表示组件的内部数据。而props是外部传入组件的数据,类似vue中的data
。
8.1、定义并初始值
//类组件
class Vid extends React.Component{
constructor(props){
super()
//构造函数里定义并初始化
this.state = {
age:13
}
}
render=()=>{
//此处要箭头函数,因为内部this指向改变了
return (<div>
{/*获取state里的age*/}
<p>年龄:{this.state.age}</p>
</div>)
}
}
ReactDOM.render(
<div>
<Vid></Vid>
</div>
,
document.getElementById('box')
)
8.2、读取状态
this.state.属性名
8.3、修改状态
必须调用setState()函数,不要直接赋值,而且,setState()函数是异步的。
- 1、修改状态时,必须要调用setState。因为,只要调用了setState函数,那就会调用了render()。如果直接赋值,不会把数据响应式地渲染到DOM上。(即:没有调render()函数)
//类组件
class Vid extends React.Component{
constructor(props){
super()
this.state = {
age:13
}
}
render=()=>{
//此处要箭头函数,因为内部this指向改变了
return (<div>
{/*获取state里的age*/}
<p>年龄:{this.state.age}</p>
<input type="button" value="点击年龄加1" onClick={()=>this.change()}/>
</div>)
}
change(){
//改变state里age的值
this.setState({
age:18
})
}
}
ReactDOM.render(
<div>
<Vid></Vid>
</div>
,
document.getElementById('box')
)
- 2、setState()函数是异步的
change() {
//改变state里age的值
console.log('this.state.age:(前)', this.state.age);
this.setState(function (prevState) {
console.log('改变状态前干的事');
return {
age: 18
}
}, function () {
//改变状态后打印值
console.log("this.state.age", this.state.age);
})
console.log('this.state.age:(后)', this.state.age);
}
注意:直接修改state属性的值不会重新渲染组件 ,
-
补充
给引用类型的某个属性赋值(也就是this.state里的某个属性值是对象)
change(){
this.setState({
desc:{
...this.state.desc,
date:(new Date()).toLocaleString()
}
});
}
今天写了一天的博客!!!