1、前言javascript
为何要去学习React呢,关于前端三大框架Angular,Vue,React其实都得去学吧,由于你们都在用啊,你们都再谈论啊,面试什么的都要求,没办法,曾几什么时候,你们都说求求大佬们别坑新了,别出框架了,老子孩子孙子都学不动了。其实我jiao的吧,技术,不就是一直更新的,新的技术代替老的技术,说不定有一天,三大框架也会被其余东西代替,就想之前的jquery同样,没什么的,我以为大佬们出一个框架的时间,比起咱们去学习的时间来讲真的是太多了,这东西思想都是同样的,都是通的,若是真的去认真学习一下,也就几天的时间。技多不压身,就这样吧。php
关于为何要学习React,就说如下几点吧html
其实让我总结起来就三点:1.用的人多 2.用的人多 3.用的人多前端
2、React中的几个核心概念vue
好比咱们的页面上有一个dom元素,输出这个dom元素(暂且叫真实的dom元素)java
<body> <div id="box" title="这是一个dom元素" data-value="div"> 这是一个文本节点 <p>p标签</p> </div> <script> var div = document.getElementById('box'); console.log(div); </script> </body>
那么接下来咱们来用虚拟DOM的方法来描述这个dom元素,也就是用一个js对象来表示这个dom元素的全部东西,未来咱们也能用这个虚拟的dom来渲染出来真实的dom react
<script> var div = { tagName:'div',//html标签名 attrs:{ id:'box', title:'这是一个dom元素', 'data-value':'div' }, childrens:[ '这是一个文本节点', { tagName:'p', attrs:null, childrens:[ 'p标签' ] } ] } </script>
就这样,咱们就用js对象描述了一个完整的dom元素。jquery
2.2 Diff算法webpack
所谓Diff,也就是Different,就是差别的意思,React是比较数据变换先后虚拟dom的差别来更新界面的上dom元素的,而且只是更新改变的dom节点的各项属性值,不改变的就不去更新。程序员
在咱们传统的操做dom的方式中,好比一个集合,当里边的某条数据变化,咱们通常会从新赋值集合,而且使用模板引擎从新调用一下渲染方法,这样一来是更新了所有的dom节点,相比而言就不那么高效了。
至于算法到底是怎么来的咱们也没必要深究了。也就是对比上边的两个js对象,有没有差别啥的,而后作标记,须要更新那些东西,而后再反馈到界面上。
3、第一个HelloWorld程序
看了很多教程,上来就是脚手架什么的 ,一会儿怼一大堆东西,都不知道什么玩意。也有用webpack的,直接开始模块化开发,初学者不建议这样,弄的都是一头雾水的。其实react,vue,angular这些框架都能和使用jquery同样,页面引入相关js就好了,这篇文章最主要的仍是写给初学者和后端,前端可能就不须要了。
3.1 首先要引入相关js,博主已经给准备好了,点击下载lib.zip,页面代码以下,也是很是的简单大气上档次:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="lib/babel.js"></script> <script src="lib/react.development.js"></script> <script src="lib/react-dom.development.js"></script> </head> <body> <div id="app"></div> <script> console.log(React, ReactDOM); </script> </body> </html>
很简单,和你刚学jquery是同样的,引入以后输出一下React的两个对象,没问题就能够开始了。
3.2 建立虚拟dom元素,渲染到页面上
<body> <div id="app"></div> <script> // 这是 建立虚拟DOM元素的 API <h1 title="h1标签" id="myh1">hello world</h1> // 第一个参数: 字符串类型的参数,表示要建立的标签的名称 // 第二个参数:对象类型的参数, 表示 建立的元素的属性节点 // 第三个参数: 子节点 var h1 = React.createElement('h1', { title: 'h1标签', id: 'myh1' }, 'hello world') // 3. 渲染虚拟DOM元素 // 参数1: 表示要渲染的虚拟DOM对象 // 参数2: 指定容器,注意:这里不能直接放 容器元素的Id字符串,须要放一个容器的DOM对象 ReactDOM.render(h1, document.getElementById('app')) </script> </body>
运行结果以下:
4、JSX语法
4.1 html代码和js代码混编
建立虚拟dom着实麻烦,若是有嵌套状况就更麻烦了,要写好半天,因而React提供了一套新的建立虚拟dom的方法,这是一新语法,意思就是js的扩展语法,可让咱们直接在js代码中写html标签和js代码,意思就是js和html代码混写。引用李纳斯的一句名言:talk is cheap,show me your code,不懂的话,翻译成汉语就是:废话少说,放码过来。
<body> <div id="app"></div> <script> var h1 = <h1 title="h1标签" id="myh1">hello world</h1>; //没错,就是这样直接写标签,不加'',不是字符串 ReactDOM.render(h1, document.getElementById('app')) </script> </body>
运行结果以下:
没错,报错了,由于 var h1 = <h1 title="h1标签" id="myh1">hello world</h1>; 是新语法,如今好多浏览器根本不认识,因此确定报错。别忘了,咱们以前还引入了一文件就是babel.js,这货就是用来帮浏览器来认这样的代码的,另外还有一些很新的es6的语法,浏览器也不认识,也须要它的帮助。
接下来咱们就来使用它,就是把<script></script>标签 改为 <script type="text/babel"></script>,text/babel就是 babel.js来识别的,它会把里边的高级代码转换成浏览器能认识的代码,自己这段script 浏览器看见他的type属性是不认识的,因此不会管它。
修改以后以下:
4.2 加入js代码(数据处理)
接下来咱们写点js代码,渲染一些数据,为了区别在html标签中的js代码,须要用{} 把js代码包起来,这个语法好多模板框架都有,vue,angular里边是{{}} ,也都相似,都差很少。咱们来渲染一个列表
<body> <div id="app"></div> <script type="text/babel"> // jsx语法下的数组 var fruits = [ <li key="1">苹果</li>, <li key="2">香蕉</li>, <li key="3">橘子</li> ] // js语法下的数组 var todos = [ { id: 1, title: '吃饭' }, { id: 2, title: 'sleep' }, { id: 3, title: '大' } ] // 调用map方法 生成一个jsx数组 var todoLis = todos.map(item => { return <li key={item.id}>{item.title}</li> }) // 推荐jsx语法中元素用括号包起来 var element = ( <div> {/* 在 jsx 中,绑定数组成员会直接把成员渲染到这里 (jsx中的注释要写在花括号) */} <ul>{fruits}</ul> <ul> {/* 直接绑定一个数据 */} {todoLis} </ul> {/* 直接在标签中动态生成一个数组 */} <ul> { todos.map(item => { return <li key={item.id}>{item.title}</li> }) } </ul> </div> ) ReactDOM.render(element, document.getElementById('app')) </script> </body>
运行结果以下:
4.3 加入js代码(事件处理)
事件名称和原生事件都同样,只不过写法上注意一点大小写,由于后边是js代码,全部用{}包起来
<body> <div id="app"></div> <script type="text/babel"> function handleClick () { window.alert('hello') } // 1. 使用驼峰命名 // 2. 必须绑定一个函数 // 3. 不能使用字符串的方式,必定要使用 {函数} 来绑定 var element = ( <div> <button onClick={handleClick}>点我</button> {/* 直接绑定一个匿名函数 */} <button onClick={() => alert('hello world')}>行内处理</button> </div> ) ReactDOM.render(element, document.getElementById('app')) </script> </body>
5、组件化编程
React最大的特色就是组件化编程,也就是模块化编程,可是模块化是对于业务代码来讲的,好比js代码中一个功能块,java中的一个utils包,c#中的一个dll类库,组件化其实也是一个块,只不是是对于界面上ui来讲,好比说一个日历组件,在界面上展示出来就是一个日历,不管是模块化仍是组件化都有一个特色,那就是拿过来到哪里都能用。组件化编程就是要求咱们把页面分红一块一块的,这样一来页面结构清晰,每个组件控制每一块页面,互不影响,固然你有时候也能够把一个页面当作一个组件,当这个页面实在是没多少东西很简单的时候就能够这样作。
5.1 函数式组件
函数式组件使用时,直接定义一个函数,函数名称大写,之于为何大写,这里内部React把 一个组件当作一个类了,以后咱们会介绍以类的方式来建立组件,使用的时候在render函数里边放一个以函数名 命名的标签就好了。但标签和双标签都行。
<body> <div id="app"></div> <script type="text/babel"> // 组件的名字首字母必须大写 function AppHeader () { return ( {/* jsx中若是要给标签加类名的话,用className属性,由于class在js代码中为关键字*/} <div className="header"> <h1>头部</h1> </div> ) } //使用方式以下 用一个闭合的标签 单标签和双标签都行 //ReactDOM.render(<AppHeader></AppHeader>, document.getElementById('app')) ReactDOM.render(<AppHeader/>, document.getElementById('app')) </script> </body>
固然咱们也能够为组件传递数据,传递数据的方式是在标签上加属性值,这里能够写js代码,在组件的函数中会以形参的方式传递过来,传递过来的数据是只读的,咱们并不能做修改
<body> <div id="app"></div> <script type="text/babel"> var dog = { name:'haha', age:5, sex:'公' } // 组件的名字首字母必须大写 function AppHeader (props) { //组件上传递的数据会做为形参传递过来,形参名字什么都无所谓,通常咱们props 意思就是属性 //可是这个属性是只读的,咱们不能修改 props.name = '1' console.log(props); //jsx中若是要给标签加类名的话,用className属性,由于class在js代码中为关键字 return ( <div className="header"> <h1>头部,{props.name},{props.age}</h1> </div> ) } //使用方式以下 用一个闭合的标签 单标签和双标签都行 //ReactDOM.render(<AppHeader></AppHeader>, document.getElementById('app')) //传递给AppHeader组件的数据 ReactDOM.render(<AppHeader name={dog.name} age={dog.age}/>, document.getElementById('app')) </script> </body>
5.2 class方式建立的组件
React推荐咱们用class方式建立组件,建立的组件用class关键字,而且继承React.Component,这才会把这个类标记为一个组件,在组件中,必须声明一个render方法,返回jsx元素,内部react会调用这个方法帮咱们渲染组件。
<body> <div id="app"></div> <script type="text/babel"> // 1. class 组件类,必须继承自 React.Component 才是一个组件类,不然就是一个普通的类 // 2. 在组件类中,必须经过 render 渲染函数返回组件模板 // 3. 接下来就能够在其它能访问到这个组件类的做用域中去使用这个组件了 class MyComponent extends React.Component { render () { return ( <div> <h1>My Component</h1> </div> ) } } var element = <MyComponent /> ReactDOM.render(element, document.getElementById('app')) </script> </body>
既然是class,就会有本身的实例数据,接下来咱们建立一个具备本身私有数据的组件,咱们在class内部定义一个state变量来存储数据
<body> <div id="app"></div> <script type="text/babel"> // EcmaScript 6 Class class AppFooter extends React.Component { constructor () { super() // state 就是组件的状态,也就是把数据驱动视图的数据初始化到 state 中 // state 相似于 Vue 中的 data this.state = { foo: 'bar' } } render () { return ( <div className="footer"> <p>底部 {this.state.foo}</p> </div> ) } } ReactDOM.render(<AppFooter/>, document.getElementById('app')) </script> </body>
5.3 两种方式的对比
其实咱们上边以class方式建立的带有state变量的组件 就叫作有状态的组件,这中组件有本身的私有数据,不和外边有接触,而且数据还能够更改,这样咱们就真正实现了组件化,想用的时候随时随地拿一个实例就好了。根据实例不一样的数据渲染成不一样状态的组件。
其实这个state就相似vue中的data了。第一种函数式建立的方法,没有本身数据,且建立方式过于分离,适合那种简单且不牵扯到数据变化的静态纯展示的组件。
6、真正的使用组件
接下来咱们建立一个功能比较完成的商品列表组件,react在渲染列表数据的时候 要给每一个项目添加一个key属性来保证惟一,这样的话React更新dom的时候确保每项的状态一直保证正确,若是不加的话可能会有一些问题。
<body> <div id="app"></div> <script type="text/babel"> class ProductList extends React.Component { constructor () { // 若是子类加入了 constructor 构造函数,则必定要手动调用父类的构造函数 super super() // React 组件须要经过手动为组件类添加 state 成员来初始化:ViewModel // state 等价于 Vue 中的 data // 接下来就能够在该组件管理的模板中经过 {} 来访问绑定数据了 this.state = { products:[ { id:1, name:'iphone x', price:8999 }, { id:2, name:'xiao mi 8', price:2999 } ] } } render () { return ( <div> <ul> { this.state.products.map(item => { return (<li key={item.id}> <span>名称:{item.name}</span> <span>价格:{item.price}</span> <button onClick={this.show.bind(this,item)}>获取商品</button> <button onClick={this.add.bind(this)}>添加商品</button> </li>) }) } </ul> </div> ) } show (item) { console.log(item) // console.log(this) // 默认是 window 这里咱们采用this.show.bind(this) 把this指针改为当前组件 //这样咱们就能能用this 调用 当前组件里的 数据(state)和方法了。 } add(){ // React 不是使用的相似于 Vue 中的 Object.defineProperty() 方式 get、set // this.state.message = 'hello world' // React中没有双向绑定的功能,(吐槽一下,不知道为何没设计,感受这是和vue比较时的一大劣势) // 如今只须要知道,若是要修改 state 中的数据而且但愿获得视图更新,则必定要使用 // this.setState 方法 // this.setState({ // message: 'hello world' // }) var products = this.state.products; products.push({ id:products.length+1, name:'华为 p30', price:4999 }) this.setState({ products:products }) console.log(this.state) } } ReactDOM.render(<ProductList/>, document.getElementById('app')) </script> </body>
运行结果以下,点击相关按钮可看到结果
7、总结
本篇React教程只是为了新手和一些后端人员学习,学完以后知道React是什么就能够了。其实若是要用React也彻底能够这么来用,对于后端人员来讲,引入相关js就好了。不过前端确定都用webpack工程化开发,各类配置各类打包至关麻烦。有人说脚手架了,其实脚手架也就是把经常使用的配置给你生成好了。这些都是工具吧,你想用就去学一点,关键仍是技术吧。就像前端开发,能用的编辑器不得和你亲戚同样多。
一直有同窗说,脚手架是什么东西。脚手架就是框架啊,你本身慢慢一行代码一行代码的配也行啊,就好比你搭建ssm框架,mvc框架,三层框架,代码生成器生成一坨坨的东西。都一个意思。其实我一直很讨厌官方定义的一些东西,就好比至今我都不知道socket 为何叫套接字编程,难道是中国人硬怼过来的。
感受后端学习这些框架其实很简单的,由于思想在里边,并且前端好多东西其实都在有意无心的日后端转。我真的以为React的jsx语法 其实和jsp 或者 aspx ,甚至和php也差很少吧 都是在html代码中混写逻辑代码。
至于其余框架,Angular感受实在过重了,其实我更爱vue,各有优缺点吧。反正天下框架一大抄吧,不对,文化人读书人的事怎能说抄呢,是吸收精华,去其糟粕,吸取外来文化,为我全部,不要说三大框架,就是各类编程语言里的框架都能看见里边有相同的影子,由于毕竟编程这个思想是同样的啊,你不满意,就从新造一个,我不满意,我也从新写一个,百度不是还出了一个san,没什么好很差吧,用起来舒服就行,能提升效率提升生产力就行。你们都是混口饭吃,何须纠结来纠结去呢,好了就去学就去使用,很差了就换一个。
算了不扯淡了,不过这是我一向的风格,就算是学习技术的文章,也不想去那么很严肃,很正式,毕竟,学东西都够累了,还不能吐槽几句。