react学习笔记

React
 
时代的发展
1.jq dom操作时代,面向过程开发--seajs requirejs(2012年左右-2014年 grunt gulp 前端构建工具)模块化的开发(把一个功能封装成一个js文件,对外通过module.exports暴露方法,---14年至今 组件化开发 dom js css都封装到一个文件 然后暴露出去 通过es6的export,框架就这个文件转成自定义的html标签。)
2.我们react.js用的版本是15.5的。
3.react.js 核心库(15.5),react-dom.min.js(将虚拟dom转换成真实的dom插入到页面中),babel.js(转es6和jsx语法)
4.ReactDOM.render()函数把组件渲染成真实的DOM,并插入到DOM中
5.render函数表示当前组件的模板
 

 
CommonJS,AMD,CMD //模块化开发的规范
1.CommonJS
   CommonJS就是为JS的表现来制定规范,因为js没有模块的功能所以CommonJS应运而生,它希望js可以在任何地方运行,不只是浏览器中。
   CommonJS定义的模块分为:{模块引用(require)} {模块定义(exports)} {模块标识(module)}
   require()用来引入外部模块;exports对象用于导出当前模块的方法或变量,唯一的导出口;module对象就代表模块本身。
   CommonJS是主要为了JS在后端的表现制定的,他是不适合前端的。
在node中:
   Node应用由模块组成,采用CommonJS模块规范。根据这个规范,每一个文件就是一个模块,有自己的作用域,在每一个文件里面定义的变量,函数,类,都是私有的,对其他的文件是不可见的。
   CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,他的exports属性(即module.exports)是对外的接口,加载某个模块,其实是加载该模块的module.exports属性。require方法用于加载模块。
2.AMD CMD
   AMD规范:是 RequireJS 在推广过程中对模块定义的规范化产出的,而CMD规范:是SeaJS 在推广过程中对模块定义的规范化产出的。
   AMD(异步模块定义)出现了,它就主要为前端JS的表现制定规范,CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。AMD规范则是非同步加载模块,允许指定回调函数,由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。
define( id?, dependencies?, factory );
 
1.seajs:
   一个Web模块加载框架,追求简单、自然的代码书写和组织方式,:Sea.js 遵循 CMD 规范,模块化JS代码。依赖的自动加载、配置的简洁清晰,可以让程序员更多地专注编码。
优点:
1).提高可维护性。
2).模块化编程。
3).动态加载,前端性能优化
缺点:
1).学习文档偏少且混乱,会更改团队使用JS的编写习惯,必须使用模块化编程。
2).不太适合团队目前的情况,多JS文件但少改动,动态加载优势和模块化优势不明显。
3). 需要配套使用SPM工具,JS的打包和管理工具。
 
2.gulp 和 grunt
自动化构建工具,能够优化前端的工作流程,更加效率的开发,比如编码的时候,它会自动帮你刷新页面,压缩你的js,css代码,编译less等等。总之,通过gulp和grunt,配置一些插件,你很多繁琐的需要手动操作的事情它自动帮你完成,非常高效率,nice!
 
3.browserify / webpack   seajs / requirejs
这四个都是JS模块化的方案。其中seajs / require 是一种类型,browserify / webpack 是另一种类型。
seajs / require : 是一种在线"编译" 模块的方案,相当于在页面上加载一个 CMD/AMD 解释器。这样浏览器就认识了 define、exports、module 这些东西。也就实现了模块化。
browserify / webpack : 是一个预编译模块的方案,相比于上面 ,这个方案更加智能。没用过browserify,这里以webpack为例。首先,它是预编译的,不需要在浏览器中加载解释器。另外,你在本地直接写JS,不管是 AMD / CMD / ES6 风格的模块化,它都能认识,并且编译成浏览器认识的JS。
总结:Gulp是一个工具,而webpack等等是模块化方案。Gulp也可以配置seajs、requirejs甚至webpack的插件。
好图:
基础
1.jsx
1)添加自定义属性,需要使用data-前缀(希望当前的这个数据显示在真实的dom中,需要data-)
2)样式添加,内联样式,style,className
3 ) 注释
4)数组展开
5)变量{}
6)render只能有一个父节点
 
2.组件
1)组件的定义
2)复合组件
3)组件的props:从父组件到子组件的传递,父组件通过调用子组件,定义一个组件名,子组件通过this.props.属性名得到这个数据,并且在子组件中定义propTypes来进行属性的验证。
4)默认的props(getDefaultProps)
属性的(props)验证:
propTypes:组件的健壮性---容错率(对传进来的属性进行验证,告诉开发者你传错数据了)
{
   msg:PropTypes.oneOf([123,456]) //只能传这两个参数中的一个   
}
 3.状态
之前的:
我们可以在父组件中设置state,(并通过在子组件上使用props将其传递到子组件中)--数据驱动,在render函数中设置this.state...来获取父组件传递的值。
当前页面中显示的关注是从父节点或者父组件来的,点击切换的时候,是当前这个组件自己的状态。总结:状态是自己的状态,是用来改变视图的。
 
什么是状态:数据就是状态 ,数据改变就是状态改变。
getInitialState:初始化当前组件的内部状态
state:定义组件内部的数据,这个内部的数据就是状态
数据驱动:数据驱动视图的变化,状态改变,数据进而改变。
状态和props的区别:props是用于父组件向子组件传递数据,但是没有办法直接去改变从父组件传过来的值,state定义组件内部的数据,状态改变,数据进而改变,数据驱动视图的变化 。
{num:this.state.num++}---num值没有改变:当你有多个状态的时候,调用render函数是异步的,react更新视图是异步的。如果想要状态更新成功之后,在上一次状态的基础上改变,通过preSate。
 
如果子组件能够擅自改变父组件传过来的值,页面会显得很混乱。当前这个子组件和父组件就耦合了,就复用不了了。
单向数据流:数据只能从父组件流向子组件,而不能在子组件中直接修改父组件的值
 
es6--class:
1)constructor:当前的子类的实例默认情况下面没有自己的this对象,必须显示的定义这个constructor 函数,并且调用super(),这个this是父节点的this,当我们去new 这个子类的时候,这个this就指向这个子类的实例,render里面才能调用到这个this。
2)实例方法:handle里面的this不知道是谁,通过类的继承,在实例上面增加方法的时候,默认情况下是拿不到this的,为什么render函数里面知道这个this呢,是因为模板知道这个this是谁。
3)this.handleClick = this.handleClick.bind(this);
 
在class Concat extends React.Component 中我们是声明该class,因为this具体是由其上下文决定的,因此在类定义中我们无法得知this用法。
通过显示的定义constructor()函数,并且调用super(),这个this指向的是父节点的this,通过new一个Concat实例,这个this就指向new出来的Concat实例,render() 函数中 this.state.liked 的this上下文也是该实例。
但是在原来 React.createClass 中,handleClick() 在onClick事件触发的时候,会自动绑定到Concat实例上,这时候该函数的this的上下文就是该实例。
不过在ES6的class的写法中,Facebook取消了自动绑定,给虚拟dom绑定一个onclick事件的时候,传递的是一个匿名函数,获取的是这个函数的引用,js中是值传递,所以匿名函数中运行的上下文不知道是哪里。
所以实例化Concat后,handleClick()的上下文this指向的是这个dom,但是这个dom又不是真实的dom,所以react返回一个null回来。
 

 
4.事件
1)handle(e){}:默认情况下会把event对象作为第一个参数传入回调函数 
2)e.target.dataset:通过dataset可以拿到当前dom上data-开头的属性
 

 
5.生命周期
1)什么是生命周期
从new一个组件开始,再到这个组件被销毁,就称这个过程为生命周期。
Mounting:插入真实的DOM阶段
Updating:当状态更新的时候
Unmounting:移除真实的DOM阶段
2)生命周期钩子函数:在生命周期每个阶段的回调函数称之为生命周期钩子函数(针对于每一个阶段要做的事情--你的业务逻辑),当这个组件执行到这个阶段后,就调用这个函数。
3)生命周期方法
componentWillMount:在插入真实dom前调用,看不到数据的一个变化的过程
componentDidMount:当组件第一次插入到真实的dom以后调用
componentWillReceiveProps:组件接收到一个新的prop时被调用,初始化render时不会被调用,有一个newProps参数,代表新的props。
shouldComponentUpdate:在组件接收到新的props和state时触发,可以确认更不更新数据,return true接收新传来的props和states
,同意更新视图,return false就不会接受新传来的props和state,不同意更新视图。有newProps,newState两个参数,代表新的props和state 。
componentWillUpdate:在组件接收到新的props和state但还没有render时调用(更新之前),有nextProps,nextState两个参数,代表新的props和state。
componentDidUpdate:组件更新完成之后调用,有prevProps,prevState两个参数,代表更新之前的值。
componentWillUnmount:当组件从DOM中移除的时候调用
 

 
6.条件渲染
1)在 React 中,你可以创建不同的组件来封装各种你需要的行为。然后还可以根据应用的状态变化只渲染其中的一部分。
React 中的条件渲染和 JavaScript 中的一致,使用 JavaScript 操作符 if 或条件运算符来创建表示当前状态的元素,然后让 React 根据它们来更新 UI。放在render函数里面,做判断,将结果放在一个变量里面,再在return里面渲染出来
 

 
7.列表
key:key属性相当于给列表中的每个元素增加一个唯一值。目的在dom中的某些元素被增加或者删除的时候帮助react识别那个元素发生了变化。(为每一个对象指定一个key,让key指向这个唯一值,react通过这个key知道操作的是哪一个)
 

 
8.表单
1)受控组件:通过设置input的value属性, 无法改变输入框值,value='',不能操控。非受控组件,没有value,可以输入值
2)通过传递一个函数给子组件,当子组件的数据变化的时候,执行传递过去的函数,在父组件当中预先定义好传给子组件的函数。
 

 
9.ref
如果你想对dom节点进行操作,可以在文本框里添加一个属性ref
总结:必须获取真实的 DOM节点,虚拟DOM是拿不到用户输入的。为了做到这一点,文本输入框必须有一个 ref 属性,然后 this.refs.[refName] 就会返回这个真实的DOM节点。需要注意的是,由于 this.refs.[refName] 属性获取的是真实DOM,所以必须等到虚拟DOM插入文档以后,才能使用这个属性,否则会报错。
<input ref="myInput" /> :添加
var input = this.refs.myInput;获取
ref还可以接受一个函数
<input type="text" ref={(input) => { this.textInput = input; }} /> //ref 回调接收了当前的 DOM 元素作为参数
 

10.react路由
 
1)脚手架:
 
cnpm install -g create-react-app
create-react-app my-app
create-react-app -v
 
src是用来存放组件的(组件和组件的样式),public目录是用来存放静态资源的(通过link,src标签引入)。
2)根据hash值来进行页面的切换
3)单页面应用:在浏览器不刷新的情况下面,让不同的组件在唯一的html文件中切换。
4)url变化但是浏览器不刷新-----动态为url添加hash值(hash不会触发浏览器刷新,根据hash来定位当前应该加载什么组件)
5)npm run start:运行项目
6)安装路由
cnpm i --save react-router@2(一般用版本2)
cnpm i --save prop-types(因为react15.5剔除掉了它,用于属性验证)
7)registerServiceWorker.js:PWA,在桌面上面生成图标,将页面保存成一个个图标。只有chrome支持,处理离线
8)e.target.dataset
 
 
8)撸~
webpack的入口文件是index.js
最外层的组件是app.js
 
Router:路由器Router就是React的一个组件,Router组件本身只是一个容器,真正的路由要通过Route组件定义。
Route:Route组件定义了URL路径与组件的对应关系。你可以同时使用多个Route组件。Route组件还可以嵌套。
IndexRoute:指定默认情况下加载的子组件,<IndexRoute component={Content}/> 显示的指定Content是根路由的子组件。
Redirect:该组件用于路由的跳转,即用户访问一个路由,会自动跳转到另一个路由。
IndexRedirect:组件用于访问根路由的时候,将用户重定向到某个子组件。
Link:用于取代<a>元素,生成一个链接,允许用户点击后跳转到另一个路由。它基本上就是<a>元素的React 版本,可以接收Router的状态。如果希望当前的路由与其他路由有不同样式,这时可以使用Link组件的activeStyle属性。
 
histroy 属性:Router组件的history属性,用来监听浏览器地址栏的变化,并将URL解析成一个地址对象,供 React Router 匹配。
1) hashHistory:路由将通过URL的hash部分(#)切换,URL的形式类似example.com/#/some/path。
2) browserHistory:浏览器的路由就不再通过Hash完成了,而显示正常的路径example.com/some/path,背后调用的是浏览器的History API。(从hash值得路由切换变换为路径切换,相当于向后台发了一个请求,如果后台配置不对,就会报404,但是history api帮我们处理了,你发送get请求,都返回给你一个index.html页面给你(单页面),就不会出现404情况了)
两者区别:History API 提供了 pushState() 和 replaceState() 方法来增加或替换历史记录。而 hash 没有相应的方法,所以并没有替换历史记录的功能。另一个原因是 hash 部分并不会被浏览器发送到服务端,也就是说不管是请求 http://domain.com/index.html#foo 还是 http://domain.com/index.html#bar ,服务只知道请求了 index.html 并不知道 hash 部分的细节。而 History API 需要服务端支持,这样服务端能获取请求细节。
 
动态路由:当用户匹配到user/123或者user/343都加在User这个组件,后面这个123就相当于一个变量,获取到这个变量,向后台发送请求,后台根据这个变量查询到相关数据,再响应给前端
 
11. 总结
1)组件的作用域都是独立的,显示的数据通常是父组件传递进来的。
2)给组件传递数据的方式有2种,第一种是使用组件的 props 通过 this.props.xx来获取;通过组件的innerHTML 来传递 ,使用 this.props.children 来获取。
3)return()使用小括号包起来的是为了换行。
4)this.props.children 拿到当前使用这个组件的时候传的innerHTML的值。
 
 
 
项目总结
1
setState({ 
     value:''
})
驱动视图的改变
this.state.value='' 
仅仅只是改变value的值,不驱动视图的改变
 
2
componentDidMount(){}
在第一次插入真实的dom之后调用
 
componentWillReceiveProps(){}
shouldComponentUpdate(){}
componentWillUpdate(){}
在第一次渲染DOM并且有接受外来的props的时候并不会被调用,通过父组件调用一些事件再传值才会被调用 和 通过一些事件驱动视图的时候才会被调用,并且是在render函数之前调用
 
3 localstorage的使用
注册账号的话,是将账号以JSON字符串的方式存进storage中,再以JSON对象的方式读出来
 
4 动态路由 
user / : id  当用户匹配到user/123或者user/343的时候,后面这个123就相当于一个变量,通过Link或者browserHistory标签将这个变量带到User组件中,用this.props.params获取到这个变量,根据变量的值向后台发送不同的请求,后台根据这个变量查询到相关数据,再响应给前端,前端做相应的处理。比如job详情页面,加载的都只是job这个组件,通过不同的url带上不同的参数加载到这个组件的时候,根据参数的不同显示不同的详情页面。
经常看到一些name?id=1这种url,这种一般是get方式带上参数
 
5 业务逻辑
1)加载更多,首先读出所有的数据对象,放在一个数组里arr,定义一个截取标记idx,从0开始,如果每页只加载5条的话,arr.slice(idx,idx+5),在更新状态并且更新idx的值this.state.idx=...
2)
 
6 history
 回退
 
 
 
 
 

转载于:https://www.cnblogs.com/JackSmall/p/8577019.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值