react-day01
前言:
为了大家容易上手,我们循序渐进,由简到难,一步一步来。用ES5方式编写React语法,后期开发使用的是ES6+webpack+构建的方式编写项目。
如果以下子将所有知识点罗列出来,大家肯定容易蒙圈,所以首先掌握基础语法。
本节知识点base基础+JSX语法
主体:
(1)hello react
  
此时刷新页面,发现报错。原因在于脚本里面写的是JSX代码,所以需要修改type为text/babel
  
babel:
    作用:将ES6转为ES5、将JSX语法解析为JS语法
之所以说是JSX语法,分析如下
1、JS函数语法
  
2、传参不是字符串,而是HTML语法(XML简易版)
  
因为页面无法直接解析,所以需要通过babel解析。但这里的 babel主要依赖第三方包配合解析
  
如果将babel.min.js注释,则无法正常解析,页面为空,且不会报错
  
   
所以JSX的语法解析主要依赖type=text/babel配合第三包完成
  
小结: 1、本质:JS的一套视图层框架 2、作用:高效渲染DOM和维护DOM层
3、来源:Facebook打造,为了提升交互效率,全球最大的交互社区,页面响应用户操作过多,容易造成卡顿,所以React则致力与DOM层的渲染响应和维护
(2)JSX语法解析
案例1:
map语法:渲染无序列表
  
   
JSX语法:
{}按照JS语法进行解析
<>按照XML语法进行解析
案例2:
  
   
注意:循环时,每个列表元素需要添加key,作为唯一元素索引... ...,简单理解为状态跟踪(Diff微分算法)
(3)基础组件与组件化
组件化概念:
首先要了解一点:在React里,整体就是一个组件化设计,增强可复用性和维护性
对比之前的简单数据、XML嵌套数组,这里我们再次加大数据复杂度
  
这里会看到JSX的render里的return方法使用了(),详解React之JSX里render中return方法添加括号()或者[].
此时render的第一个参数优点累赘繁多,所以接下来举个案例,将其提取出去
  
我们可以看到,setInterval定时器里调用函数时没有加函数执行符(),详解浅谈JS之常问问题:setInterval和setTimeout调用函数为什么不加小括号()???.
接下来看下组件化,首先创建组件,React里创建组件有两种方法,如下所示
注意: 这里因为React的相关依赖包版本问题,我们换用其他版本(V16之前的版本)去进行测试,将之前的依赖包一一替换掉 <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react.min.js"></script> <script src="http://static.runoob.com/assets/react/react-0.14.7/build/react-dom.min.js"></script> <script src="http://static.runoob.com/assets/react/browser.min.js"></script>
  
1、第一种方法为React.createClass({})
  
2、第二种方法为ES的class...extends...(ES6里Class 可以通过 extends 关键字实现继承)
  
   当然,构造器constructor主要用来来构造默认的属性和状态,这里可以省略
  
3、如果想同时使用两组件,如下所示
  
此时也可以看到组件的复用性,可以随意复用任意次数... ...
注意: 1、组件名首字母大写,采用大驼峰命名 2、render:function(){})可以简写为render(){})
关于两种创建方式的区别,详解React创建组件两种写法:React.createClass和extends Component的区别.
(4)React组件嵌套
组件之间可以互相嵌套
  
   
且组件本身也具有业务逻辑,可以在内部循环
  
注意:组件只能有一个根容器
   
组件与组件间可以互相嵌套
  
(5)组件数据交互props
父子组件间数据交互依赖props,组件交互里的数据传递
语法:this.props.attributeName属性名
  
也可以传递多个参数
  
接下来利用props做下案例完善,结合之前百度导航左右侧的案例
1、左菜单导航
  
2、右菜单导航
   
3、根组件整合渲染
  
  
4、接下来做下调整
左侧和右侧的语法类似,所以这里去掉一个,并改名,然后利用props传递数据,来进行优化
  
  
但是标签里无法直接传入数组,所以接着做下修改
  
遗留1:父组件向子组件传值,不能是数组,需要由对象包含数组引用
已解决1:
  
(6)样式添加
  
V15之前都是采用React.createClass({})方式创建组件,V16开始使用ES6的Class...extends...继承方式创建
1、添加样式(class类名)
  
  
  
2、style内联样式
  
   
也可以依次写入:注意“这里的属性名必须改为小驼峰命名法则去写”
  
注意:
1、{{}}:style直接写入时是{{}}双花括号,直接将对象引用改为对象 2、默认添加单位px:React 会自动添加 ”px” 后缀到内联样式为数字的属性后。如需使用 ”px” 以外的单位,请将此值设为数字与所需单位组成的字符串。 3、属性名小驼峰:Style 中的 key 采用小驼峰命名是为了与 JS 访问 DOM 节点的属性保持一致(例如:node.style.backgroundImage )。
浏览器引擎前缀都应以大写字母开头,除了 ms。因此,WebkitTransition 首字母为 ”W”。
  
   
(7)事件
与之前 JS和jQuery事件绑定方式不同,React的事件绑定要采用该框架的绑定方式
1、React.createClass方式创建的组件绑定事件
  
1、事件名绑定采用小驼峰 2、事件调用通过this.事件名 3、记住与render间加逗号, 4、方法位置:放到创建组件内部即可
2、V16之后的ES6的Class类继承方式创建的组件
  
1、事件名绑定采用小驼峰 2、事件调用通过this.事件名 4、方法位置:放到创建组件内部即可
不用加,逗号了
其他事件类似
  
事件绑定:
    通过this找到当前组件里的方法
1、V15版本之前创建组件方式,接下来打印this测试下
  
   
控制台输出打印this指向当前React组件实例
2、V16开始的ES6的Class继承创建组件方式,测试下this,如下所示
  
   
控制台输出结果为undefined
接着做下修改,如下所示,添加bind方法,改动this指向
  
此时点击时控制台输出如下
  
所以此时
this便指向当前组件,而不是传统操作里的window全局对象
  
1、事件命名
  
2、阻止默认事件
  
   
3、添加事件监听
  
   
   
   
或者利用箭头函数,如下所示
  
  
开发建议:
    建议直接在构造器中绑定
  
(8)React关键字: state状态
之前已经介绍过一个关键字props,用于组件间的数据交互。
state关键字:组件内部的状态
例如:
    背景色为红色,点击后变蓝
    用户当前为普通用户,充值后变成VIP会员...
之前的操作,都是基于DOM进行操作的,例如之前都是操作DOM原来的普通会员为灰色,VIP后变为红色。但React、Vue、小程序等框架里不再直接操作DOM,而是基于状态进行操作,基于组件内部状态state进行操作.所以现在部分公司在开发禁止使用jquery操作DOM。
  
   
要求:点击按钮时,“开”与“关”的状态进行切换
1、首先绑定事件
  
2、初始化state值+读取渲染
  
可以通过三目运算符进行状态切换,
3、修改state状态值
  
4、作用
页面展示数据,需要后期用户操作更改或者用户登录状态、网络请求获取渲染数据... ...
5、ES6新型Class继承方式
  
小结:
    setState会引起视图的重绘,相对于直接操作DOM来讲,React采用的虚拟DOM,即Virtual DOM技术,极大提升了重绘排版效率
  
   
   
(9)条件渲染
  
   
   
   
(10)state和props应用,区分两者
1、组件一用于显示内容
  
2、处理业务逻辑
  
   
如上所示,一个组件用于数据定义和逻辑操作,另一个组件负责调用。后期易于拆分.
木偶组价&&智能组件:
如上所示,第一个仅仅用于显示的组件称为“木偶组件(受控组件)”,
第二个称之为“智能组件(不受控组件)”,只负责业务逻辑,不进行渲染展示
(11)组件生命周期
参考之前时钟的例子。在元素渲染章节中,我们只了解了一种更新 UI 界面的方法。通过调用 ReactDOM.render() 来修改我们想要渲染的元素:
  
    接下来,我们开始封装真正可复用的 Clock 组件。它将设置自己的计时器并每秒更新一次。
1、添加props,实现组件通信,即父组件向子组件传值
  
  2、目前为止,忽略了一个关键的技术细节:Clock 组件需要设置一个计时器,并且需要每秒更新 UI
  
所以接下来,向组件中添加局部的 state
   
3、之后将计时器相关的代码添加到组件中,设置 Clock 的计时器并每秒更新它,此时,便需要用到生命周期去进行操作
在具有许多组件的应用程序中,当组件被销毁时释放所占用的资源是非常重要的。
  
   
componentDidMount() 方法会在组件已经被渲染到 DOM 中后运行,所以,最好在这里设置计时器:
接下来把计时器的 ID 保存在 this 之中(this.timerID)。 尽管 this.props 和 this.state 是 React 本身设置的,且都拥有特殊的含义,但是其实你可以向 class 中随意添加不参与数据流(比如计时器 ID)的额外字段。 我们会在 componentWillUnmount() 生命周期方法中清除计时器:
  
至此,现在时钟每秒都会刷新。
  
小结:
                        
  
  
生命周期函数为红色,不需要主动调用,到一定阶段自动执行:
  getDefaultProps初始化默认props
  getInitialState初始化state
  componentWillMount组件挂载前
  render渲染
  componentDidMount组件挂载完毕
  componentWillUnmount组件卸载前
  ShouldComponentUpdate组件是否应该更新
  componentWillUpdatez组件更新前
  componentDidUpdate组件更新完毕
  componentWillReceiveProps组件更改props后执行
运行中:对应3个分支,可以朝3个方向改变
1、卸载:触发componentWillUnmount组件卸载前的生命周期
2、状态state改变或者props改变,需要经由shouldComponentUpdate做判断,如下所示
react生命周期中的shouldComponentUpdate函数就派上用场了!shouldComponentUpdate函数是重渲染时render()函数调用前被调用的函数,
它接受两个参数:nextProps和nextState,分别表示下一个props和下一个state的值。并且,当函数返回false时候,阻止接下来的render()函数的调用,阻止组件重渲染
而返回true时,组件照常重渲染。
在render函数调用前判断:如果前后state中Number不变,通过return false阻止render调用


顺序验证如下:


完整代码:

var UpdateTime = React.createClass({ /*初始化props*/ getDefaultProps(){ console.log('初始化props---getDefaultProps') }, /*初始化state*/ getInitialState(){ console.log('初始化state---getInitialState') return{ now_date:new Date() } }, /*挂载前*/ componentWillMount(){ console.log('挂载前---componentWillMount') }, /*渲染*/ render(){ console.log('渲染---render') return ( <h1>当前时间为{this.state.now_date.toLocaleTimeString()}</h1> ) }, /*挂载完毕*/ componentDidMount(){ console.log('挂载完毕---componentDidMount') this.timer = setInterval(() => { this.setState({ // now_date: new Date() }) }, 1000) }, /*卸载前*/ componentWillUnmount(){ console.log('卸载前---componentWillUnmount') clearInterval(this.timer) }, /*判断组件是否更新shouldComponentUpdate*/ shouldComponentUpdate(nextProps,nextState){ console.log('判断组件是否更新---shouldComponentUpdate') if(nextProps.now_date == this.state.now_date){ return false }else{ return true } }, /*组件即将更新*/ componentWillUpdate(){ console.log('状态即将更新---componentWillUpdate') }, /*组件更新完毕*/ componentDidUpdate(){ console.log('组件更新完毕---componentDidUpdate') } }) ReactDOM.render(<UpdateTime />,document.getElementById('demo'))
6、生命周期函数作用:
例如网络请求放到生命周期函数的某个位置,合理执行;
页面重新渲染时,提示用户页面过大,刷新消耗流量,这个提示也可以放到合适生命周期例如componentWillUpdate里
(12)组件生命周期应用
1、首先编写基础模板
  
2、接下来要做个网络请求,将数据获取后读取展示到组件里,首先初始化state内部状态
  
接下来可以利用json-server模拟服务器API建立启动服务器,如下所示
   
3、结合生命周期读取网络接口数据,写到componentDidMount里,详见React在componentDidMount里面发送请求 .这里结合jQuery的ajax实现跨域请求
  
   
打印出来的是一个数组,所以接下来我们将初始化 的数据改下,改为数组
  
4、重定义覆盖数据
  
但此时会发现控制台报错
  
我们打印this做下测试
  
发现this指向的是ajax对象,所以这里需要更改this指向,如下所示。这里使用bind改动this指向,关于相关知识点,详见 浅谈JS中的call、apply、bind方法.
  
此时的this便指向当前组件实例。接下来覆盖之前的默认值,然后进行组件内部渲染遍历
  
最终效果如下:
  
这里会有一个问题:table表格设置边框属性border无效???详见React里table表格设置边框属性border="1"无效???.完整代码如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="./dist/react.min.js"></script> <script src="./dist/react-dom.min.js"></script> <script src="./dist/browser.min.js"></script> <script src="./dist/jquery.js"></script> <style type="text/css"> table.mytable { width: 40%; border: 2px solid #444; border-spacing: 0; } table.mytable tr,table.mytable th {border-bottom: 1px solid #444} table.mytable td,table.mytable th{ border-right: 1px solid #444; border-bottom: 1px solid #444; padding: 5px; } table.mytable tr td:last-child{ border-right: 0 } table.mytable tr:last-child td{ border-bottom: 0 } </style> </head> <body> <div id="root"></div> <script type="text/babel"> class Demo extends React.Component { constructor(props){ super(props) this.state = { usersInfo:[] } } componentDidMount(){ $.ajax({ url: "http://localhost:3000/users", type: "get", success:function(result) { this.setState({ usersInfo:result }) }.bind(this) }) } render(){ return ( <div> <h2>组件</h2> <table border="1"> <tr> <th>id</th> <th>姓名</th> <th>年纪</th> <th>性别</th> <th>工作</th> </tr> { this.state.usersInfo.map(function(item,index){ return( <tr key={index}> <td>{item.id}</td> <td>{item.username}</td> <td>{item.age}</td> <td>{item.gender}</td> <td>{item.job}</td> </tr> ) }) } </table> </div> ) } } ReactDOM.render(<Demo />,document.getElementById('root')) </script> </body> </html>
.
                    
                
                
            
        
浙公网安备 33010602011771号