React学习笔记
参考网站:http://jspang.com/2017/08/15/react_basic/
1、React起源于Facebook的内部项目
ReactJS官方地址:https://facebook.github.io/react/
GitHub地址:https://github.com/facebook/react
react特点:
虚拟DOM:React是以数据驱动的,每次数据变化React都会扫码整个虚拟DOM树,自动计算与上次虚拟DOM的差异变化,然后针对需要变化的部分进行实际的浏览器DOM更新
组件化:React可以从功能角度横向划分,将UI分解成不同组件,各组件都独立封装,整个UI是由一个个小组件构成的一个大组件,每个组件只关系自身的逻辑,彼此独立
单向数据流:Reac设计者认为数据双向绑定虽然便捷,但在复杂场景下副作用也是很明显,所以React更倾向于单向的数据流动--从父节点传递到子节点。(使用ReactLink也可以实现双向绑定,但不建议使用)
2、react.js和react-dom.js文件
react.js:实现React核心逻辑,且与具体的渲染引擎无关,从而可以跨平台共用。如果应用要迁移到React Native,这一部分逻辑是不需要改变的。
react-dom.js:包含了具体的DOM渲染更新逻辑,以及服务端渲染的逻辑,这部分就是与浏览器相关的部分
3、React.createElement( string/ReactClass type,[object props], [children ...]) 返回一个给定类型的ReactElement元素
type:必须,可以是html标签名称字符串,也是可以是ReactClass
[object props]:可选,该标签的属性,一般为null
[children ...]:可选,该元素的子节点
链接:http://www.onmpw.com/tm/xwzj/web_103.html
4、JSX的好处:
可以使用熟悉的语法仿照HTML来定义虚拟DOM
与javaScript之间等价交换,代码更加直观
5、getInitialState函数是用来设置state里面值的默认值的
必须有返回值return
1 getInitialState: function () { 2 return {enable: false} 3 }
getDefaultProps函数是用来设置state里面值的默认值的
6、props与state的区别
props不能被其所在的组件修改,从父组件传递进来的属性不会在组件内部更改;state只能在所在组件内部更改,或在外部调用setState函数对状态进行间接修改。
7、render成员函数
首先说render是一个函数,它对于组件来说,render成员函数是必需的。render函数的主要流程是检测this.props和this.state,再返回一个单一组件实例。
render函数应该是纯粹的,也就是说,在render函数内不应该修改组件state,不读写DOM信息,也不与浏览器交互。如果需要交互,应该在生命周期中进行交互。
8、react的表单--bind复用
bind方法为事件相应函数增加一个参数,事件响应函数通过该参数识别事件源
bind可以点击这里:http://www.cnblogs.com/zhaobao1830/p/8016638.html
1 <!DOCTYPE html> 2 <html lang="zh"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="x-ua-compatible" content="ie=edge"> 6 <title>表单--bind复用</title> 7 <meta name="viewport" content="width=device-width, initial-scale=1,minimum-scale=1,maximum-sacle=1,user-scalable=no"> 8 <script src="https://cdn.bootcss.com/react/15.4.2/react.min.js"></script> 9 <script src="https://cdn.bootcss.com/react/15.4.2/react-dom.min.js"></script> 10 <script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.min.js"></script> 11 </head> 12 <body> 13 <div id="demo"></div> 14 <script type="text/babel"> 15 var MyForm = React.createClass({ 16 getInitialState: function() { 17 return{ 18 username: '', 19 gender: 'man', 20 checked: true 21 } 22 }, 23 handleChange: function (name, event) { 24 var newState = {} 25 newState[name] = name === 'checked' ? event.target.checked : event.target.value 26 this.setState(newState) 27 console.log(newState) 28 }, 29 handleSubmit: function (e) { 30 e.preventDefault() 31 var is = this.state.checked ? '是' : '不是' 32 var gender = this.state.gender === 'man' ? '帅哥' : '美女' 33 alert(this.state.username+ is + gender +'.' ); 34 }, 35 render: function () { 36 return ( 37 <form onSubmit={this.handleSubmit}> 38 <label htmlFor="username">请输入您的名字:</label> 39 <input type="text" name="username" id="username" onChange={this.handleChange.bind(this, "username")} value={this.state.username}/> 40 <br/> 41 <label htmlFor="checkBox">是或否:</label> 42 <input type="checkbox" value="是否" name="checked" id="checkBox" onChange={this.handleChange.bind(this, "checked")} checked={this.state.checked}/> 43 <br/> 44 <label htmlFor="username">请选择</label> 45 <select name="gender" onChange={this.handleChange.bind(this, "gender")} value={this.state.gender}> 46 <option value="man">帅哥</option> 47 <option value="woman">美女</option> 48 </select> 49 <br/> 50 <button type="submit">提交</button> 51 </form> 52 ) 53 } 54 }) 55 ReactDOM.render( 56 <MyForm/>, 57 document.getElementById("demo") 58 ) 59 </script> 60 </body> 61 </html>
这个里面的bind,this是绑定到当前环境下,第二个参数是预设一个参数,对应的是handleChange()里的name参数
9、react表单--name复用
name复用方式直接读取表单的属性值,比bind写法少一个参数(React中事件响应函数会自动绑定this)。其原理是在所有的标签中设置统一的name属性,并将这个属性值对应为state属性,在事件响应函数中通过读取表单的name值获得state属性,从event.target.value获取用户输入的值(check控件稍有不同),要求所有相关的标签(包括input标签)都要统一设置name属性。
就是每个标签加一个name,然后判断name来进行state的更改。但是我不建议这样使用,因为为每个标签增加一个name属性值并不友好。
1 <!DOCTYPE html> 2 <html lang="zh"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="x-ua-compatible" content="ie=edge"> 6 <title>表单--name复用</title> 7 <meta name="viewport" content="width=device-width, initial-scale=1,minimum-scale=1,maximum-sacle=1,user-scalable=no"> 8 <script src="https://cdn.bootcss.com/react/15.4.2/react.min.js"></script> 9 <script src="https://cdn.bootcss.com/react/15.4.2/react-dom.min.js"></script> 10 <script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.min.js"></script> 11 </head> 12 <body> 13 <div id="demo"></div> 14 <script type="text/babel"> 15 var MyForm = React.createClass({ 16 getInitialState: function() { 17 return{ 18 username: '', 19 gender: 'man', 20 checked: true 21 } 22 }, 23 handleChange: function (event) { 24 var newState = {} 25 newState[event.target.name] = event.target.name === 'checked' ? event.target.checked : event.target.value 26 this.setState(newState) 27 console.log(newState) 28 }, 29 handleSubmit: function (e) { 30 e.preventDefault() 31 var is = this.state.checked ? '是' : '不是' 32 var gender = this.state.gender === 'man' ? '帅哥' : '美女' 33 alert(this.state.username+ is + gender +'.' ); 34 }, 35 render: function () { 36 return ( 37 <form onSubmit={this.handleSubmit}> 38 <label htmlFor="username">请输入您的名字:</label> 39 <input type="text" name="username" id="username" onChange={this.handleChange} value={this.state.username}/> 40 <br/> 41 <label htmlFor="checkBox">是或否:</label> 42 <input type="checkbox" value="是否" name="checked" id="checkBox" onChange={this.handleChange} checked={this.state.checked}/> 43 <br/> 44 <label htmlFor="username">请选择</label> 45 <select name="gender" onChange={this.handleChange} value={this.state.gender}> 46 <option value="man">帅哥</option> 47 <option value="woman">美女</option> 48 </select> 49 <br/> 50 <button type="submit">提交</button> 51 </form> 52 ) 53 } 54 }) 55 ReactDOM.render( 56 <MyForm/>, 57 document.getElementById("demo") 58 ) 59 </script> 60 </body> 61 </html>
10、在react里面,input标签有点特殊
将Input中的value绑定到state的React组件是可控组件,反之则是不可控组件
在render()函数中设置了value的<Input>是一个功能受限的组件,渲染出来的HTML元素始终保存value属性的值,即使用户输入也不会改变
1 var MyForm = React.createClass({ 2 render:function(){ 3 return( 4 <div> 5 <input type="text" value="zb" /> 6 </div> 7 ) 8 } 9 });
这时打开浏览器,value值无法改变,也无法删除,这时由React的渲染策略决定的
11、可控组件
1 <!DOCTYPE html> 2 <html lang="zh"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="x-ua-compatible" content="ie=edge"> 6 <title>Title</title> 7 <script src="https://cdn.bootcss.com/react/15.4.2/react.min.js"></script> 8 <script src="https://cdn.bootcss.com/react/15.4.2/react-dom.min.js"></script> 9 <script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.min.js"></script> 10 </head> 11 <body> 12 <div id="demo"></div> 13 <script type="text/babel"> 14 var MyForm = React.createClass({ 15 getInitialState: function () { 16 return {value: 'zb'} 17 }, 18 handleChange: function (event) { 19 this.setState({value: event.target.value}) 20 }, 21 render: function () { 22 return ( 23 <div> 24 <input type="text" value={this.state.value} onChange={this.handleChange}/> 25 </div> 26 ) 27 } 28 }); 29 ReactDOM.render( 30 <MyForm/>, 31 document.getElementById('demo') 32 ) 33 </script> 34 </body> 35 </html>
在条件允许的情况下,我们应该优先考虑编写可控组件
可控组件的特点:
1、符合React单向数据流特性,即从state流向render输出的结果
2、数据存储在state中,便于访问和处理
12、快速构建react开发环境的脚手架工具:create-react-app
地址:https://github.com/facebookincubator/create-react-app
create-react-app优点:
无需配置:官方的配置堪称完美,几乎不用你再配置任何东西,就可以上手开发项目
高集成性:集成了对React、JSX、ES6和Flow的支持
自带服务:集成了开发服务器,你可以实现开发预览一体化
热更新:保存自动更新
全兼容性:自动处理css的兼容问题,无需添加-webkit前缀
自动发布:集成好了发布成品功能,编译后直接发布,并且包含了sourcemaps功能
13、构建工具:generator-react-webpack
参考地址:http://jspang.com/2017/10/22/react-all-01/
它是需要yeoman的支持的
优点:
基于webpack构建,可以很容易的配置自己需要的webpack
支持ES6,集成了Bable-Loader
支持不同风格的CSS(sass,less,stylue)
支持PostCSS转换样式
集成了esLint功能
可以轻松配置单元测试,比如Karma和Mocha
14、React路由需要用到俩个模块:Router(路由器)和Route(路由)
exact是精确匹配的意思
React会匹配所有能匹配的路由组阶,exact可以使我们的匹配更精确。exact的值为bool型,为true是表示严格匹配,为false时为正常匹配
1 <Route path="/" component={Jspang} /> 2 <Route path="/Jspangb" component={Jspangb} /> 3 //这种情况下,输入路由"/Jspangb",会把Jspang组件也展示出来 4 5 //所以我们经常使用exact来解决这个问题。 6 <Route exact path="/" component={Jspang} /> 7 <Route path="/Jspangb" component={Jspangb} />
作为一个链接是用激活状态的,激活状态就是当我们处在这个链接时。activeClassName就是设置激活状态的样式,它接受一个类名
1 .active{ 2 color: red 3 } 4 <NavLink to='/Jspangc' activeClassName='active'>Jspangc</NavLink>
15、404页面,需要用到Switch组件
地址:http://jspang.com/2017/10/22/react-all-01/#03webpack01
Redirect组件使用
有时候我们开发中希望在程序中根据业务逻辑进行跳转,或者一个链接点击后直接跳转到其它链接。这时候可以使用Redirect组件解决。
16、路由:Router中属性和路由模式
basename属性
basename的作用是个我们增加一级导航目录,比如以前的导航目录是:http://localhost:1717/Jspangb 现在想访问同一个页面,但是路径变成http://localhost:1717/demo/Jspangb。这时候就可以使用basename属性来设置。basename属性是放在<router>标签里边的。
1 <Router basename="demo"> 2 <div> 3 <Nav/> 4 <Switch> 5 <Route exact path="/" component={Jspang} /> 6 <Route path="/Jspangb" component={Jspangb} /> 7 <Route path="/Jspangc/:param" component={Jspangc} /> 8 <Redirect from="/redirect" to="/Jspangb" /> 9 <Route component={Error} /> 10 </Switch> 11 12 </div> 13 </Router>,
forceRefresh属性
这个属性的作用是开启或者关闭React Router,也就是说如果你把forceRefresh的值设置成真,它将关闭React路由系统,而真实的去服务器端请求信息。
现在我们把forceRefresh设置成true,你会发现路由已经不能使用了。
1 <Router basename="demo" forceRefresh={true}> 2 <div> 3 <Nav/> 4 <Switch> 5 <Route exact path="/" component={Jspang} /> 6 <Route path="/Jspangb" component={Jspangb} /> 7 <Route path="/Jspangc/:param" component={Jspangc} /> 8 <Redirect from="/redirect" to="/Jspangb" /> 9 <Route component={Error} /> 10 </Switch> 11 12 </div> 13 </Router>,
这个操作经常使用在大型项目,在服务器跳转和ReactRouter切换时使用。比如作一个APP活动页面,第一次请求时我们到服务器端请求整个页面,然后请求后,整个页面DOM进行本地缓存,生成React Router实现本地单页应用。 只要设置我们的forceRefresh就可以了。
5种路由方式
我们一直在使用的路由方式是BrowserRouter,也就是浏览器的路由方式,其实React还有几种路由方式:
- BrowserRouter:浏览器的路由方式,也是我们一直在学习的路由方式,在开发中最常使用。
- HashRouter:在路径前加入#号成为一个哈希值。Hash模式的好处是,再也不会因为我们刷新而找不到我们的对应路径了。
- MemoryRouter:不存储history,所有路由过程保存在内存里,不能进行前进后退,因为地址栏没有发生任何变化。
- NativeRouter:经常配合ReactNative使用,多用于移动端,以后ReactNative课程中会详细讲解。
- StaticRouter:设置静态路由,需要和后台服务器配合设置,比如设置服务端渲染时使用。
17、prompt用法讲解
地址: http://jspang.com/2017/10/22/react-all-01/#10prompt
动态该改变when的状态那,这里做一个小实例:写一个按钮,然后设置一个power状态,通过点击按钮改变状态,来控制<Prompt>标签的启用和关闭
1 import React from 'react'; 2 import {Prompt} from 'react-router-dom'; 3 export default class jspangb extends React.Component{ 4 5 6 constructor(props){ 7 super(props); 8 this.state={ 9 power:false 10 } 11 this.changePower=this.changePower.bind(this); //备注:这个是为了给changePower绑定作用域,如果没有这个的话,方法里的this找不到 12 } 13 changePower(){ 14 alert('已经开启'); 15 this.setState({ 16 power:true 17 }) 18 } 19 20 render(){ 21 return( 22 <div> 23 <p> B页面</p> 24 <Prompt message="残忍离开?" when={this.state.power}/> 25 <button onClick={this.changePower}>启用</button> 26 </div> 27 ) 28 } 29 }