过去css
须要手动更新DOM、费力地记录每个状态;既不具有扩展性,又很难加入新的功能,就算能够,也是有着冒着很大的风险。html
不过,使用这种开发方式很难打造出极佳的用户体验。由于不管每次用户想要作点什么,都须要向服务端发送请求并等待服务端的响应,这会致使用户失去在页面上所积累的状态。前端
Reactreact
它引入了一种新的方式来处理浏览器DOM。程序员
在任什么时候间点,React都能以最小的DOM修改来更新整个应用程序。web
React本质上只关心两件事:1). 更新DOM;2). 响应事件。ajax
每次状态改变时,使用JavaScript从新渲染整个页面会很是慢,这应该归咎于读取和更新DOM的性能问题。React运用一个虚拟的DOM实现了一个很是强大的渲染系统,在React中对DOM只更新不读取。算法
React不处理Ajax、路由和数据存储,也不规定数据组织的方式。它不是一个Model-View-Controller框架。若是非要问它是什么,他就是MVC里的“V”。React的精简容许你将它集成到各类各样的系统中 。编程
React以渲染函数为基础。这些函数读入当前的状态,将其转换为目标页面上的一个虚拟表现。redux
只要React被告知状态有变化,他就会从新运行这些函数,计算出页面的一个新的虚拟表现,接着自动把结果转换成必要的DOM更新来反映新的表现。【不须要reset方式的completely update】
这种方式看上去应该比一般的JavaScript方案——按须要更新每个元素——要慢,可是React确实是这么作的:它使用了很是高效的算法,计算出虚拟页面当前版本和新版间的差别,基于这些差别对DOM进行必要的最少更新。
公认的性能瓶颈
"React除了可以组件化开发ui,还完彻底全实现了先后端的隔离"。客官,此话怎讲?
Ref: 怎样理顺react,flux,redux这些概念的关系,开发中有必要使用它们吗?
Ref: 理解 React,但不理解 Redux,该如何通俗易懂的理解 Redux?
1. 反复刷新页面,尤为是内容复杂的页面,对浏览器的渲染性能消耗很大。
2. 由交互产生的不少细腻的前端数据,其实也很难交给后台处理,由于这是咱们无处安放的临时状态
1. 根据后台数据排版生成页面,如今只是最基本的工做。
2. 当用户进行某种交互操做引发页面状态变化以后,为了不页面总体刷新,咱们须要当心翼翼地将各个相关的页面局部元素拣选出来,作适当修改,再放回原处,动做通常不会太优雅。
1. 根据肯定的交互状态(state),一古脑儿决定页面的呈现(view),这种“单向流”的开发状态对程序员来讲是思惟清晰、比较轻松的;一旦咱们须要不断手动更新view,而且改变state和view的代码还纠缠在一块儿,咱们的心里每每是崩溃的。
2. 为了让前端开发不感到崩溃,就把全部state交给后台来维护,简单粗暴地经过从新加载页面来实现view的更新是不靠谱的,咱们须要找到新的方法,来实现view的自动更新。
我脑补着facebook的某个程序员在一个月黑风高的晚上坐在公司电脑前,抿了一口浓浓的咖啡,忽然灵光一现,伴着屏幕上忽明忽暗的幽幽蓝光,在文本编辑器里写下这么一行文字:
可不能够把浏览器里的DOM tree克隆一份完整的镜像到内存,也就是所谓的“virtual DOM”,当页面的state发生变化之后,根据最新的state从新生成一份virtual DOM(至关于在内存里“刷新”整个页面),将它和以前的virtual DOM作比对(diff),而后在浏览器里只渲染被改变的那部份内容,这样浏览器的性能损耗和用户体验不就都不成问题了吗?
而咱们知道在绝大部分网页应用中js引擎的性能和内存彻底没有被充分利用,咱们正好能够火力全开,利用js的这部分性能红利,实现内存中virtual DOM的diff工做,完美!
因而React横空出世!伴随着react的崛起,相似于redux这些专一于管理state的轻量级框架也变得煊赫一时起来。
决定页面呈现的state能够经过模块属性(props)从父模块传递到子模块。
这种"树状"分流机制,有点像植物将营养(state)从根部不断运输到细枝末叶的过程。
* 传统MVC
1. 前端开发的Model至关于后台数据的镜像或缓存池,它和服务器端MVC中的Model概念一脉相承;
2. View对应页面的呈现,主要指的是和html、css相关的代码,它和服务器端MVC中的View概念也很是相近。
3. 显著的差异来自于controller:在后台应用中,用户和服务器之间的交互是经过http请求实现的,所以后台controller的表达形式是http请求的handler,而且和router(定义网站的url规则)紧密相关; 而前端应用中,用户和网页之间的交互主要是经过操做事件(例如点击鼠标、键盘输入等)实现的,所以前端的controller这里能够简单理解为各类交互事件的handler。
* 问题表象
修改Model的Controller代码像一把黄豆同样散落在了各个View组件的内部。
* 问题缘由
若是能够用某种方式把这些散落的代码单独收拢到一块儿,是否是就让这可让这张图示恢复秩序呢?好,咱们顺着这个思路想下去。
不是MVC模式错了,而是咱们压根缺乏了一个和用户交互行为有关的action抽象!所以,对model的具体操做才无法从各个view组件中被剥离出来,放到一处。
* Flux思想 - 单向流思想
1. flux与react没有直接的关系,两者是彻底独立的概念。
2. flux不是一个js库,而是一种前端代码的组织思想,好比说 redux库能够认为是一种flux思想的实现。
从代码层面而言,flux无非就是一个常见的event dispatcher,
其目的是要将以往MVC中各个View组件内的controller代码片段提取出来放到更加恰当的地方进行集中化管理,并从开发体验上实现了温馨清爽、容易驾驭的“单向流”模式。
用户在view上的交互行为(好比点击提交按钮等)应当引发state改变的时候,这个流程该怎么处理?
首先,react框架为咱们理顺了 store --> view 的“单向”工做流(store是state的容器);
而后,redux框架为咱们理顺了 view --> store 的**“单向”**工做流。
而且,react和redux都以组件化的形式能够将各自负责的功能进行灵活地组装或拆分,最大程度上确保咱们“一次只须要专一于一个局部问题”。具体来讲,分为如下步骤:
从需求出发,看看使用React须要什么:
1. React有props和state:
props 意味着:父级分发下来的属性;
state 意味着:组件内部能够自行管理的状态;
而且整个React没有数据向上回溯的能力,也就是说数据只能单向向下分发,或者自行内部消化。
理解这个是理解React和Redux的前提。
2. 通常构建的React组件内部多是一个完整的应用,它本身工做良好,你能够经过属性做为API控制它。可是更多的时候发现React根本没法让两个组件互相交流,使用对方的数据。
而后这时候不经过DOM沟通(也就是React体制内)解决的惟一办法就是提高state,将state放到共有的父组件中来管理,再做为props分发回子组件。
3. 子组件改变父组件state的办法只能是经过onClick触发父组件声明好的回调,
也就是父组件提早声明好函数或方法做为契约描述本身的state将如何变化,
再将它一样做为属性交给子组件使用。
这样就出现了一个模式:数据老是单向从顶层向下分发的,可是只有子组件回调在概念上能够回到state顶层影响数据。这样state必定程度上是响应式的。
4. 为了面临全部可能的扩展问题,最容易想到的办法就是把全部state集中放到全部组件顶层,而后分发给全部组件。
5. 为了有更好的state管理,就须要一个库来做为更专业的顶层state分发给全部React应用,这就是Redux。
让咱们回来看看重现上面结构的需求:
a. 须要回调通知state (等同于回调参数) -> action【发起的通讯请求】
b. 须要根据回调处理 (等同于父级方法) -> reducer 【对通讯请求刷选处理的过程】
c. 须要state (等同于总状态) -> store
对Redux来讲只有这三个要素:
a. action是纯声明式的数据结构,只提供事件的全部要素,不提供逻辑。
b. reducer是一个匹配函数,action的发送是全局的:全部的reducer均可以捕捉到并匹配与本身相关与否,相关就拿走action中的要素进行逻辑处理,修改store中的状态,不相关就不对state作处理原样返回。
c. store负责存储状态并能够被react api回调,发布action.
固然通常不会直接把两个库拿来用,还有一个binding叫react-redux, 提供一个Provider和connect。不少人其实看懂了redux卡在这里。
a. Provider是一个普通组件,能够做为顶层app的分发点,它只须要store属性就能够了。它会将state分发给全部被connect的组件,无论它在哪里,被嵌套多少层。
b. connect是真正的重点,它是一个科里化函数,意思是先接受两个参数(数据绑定mapStateToProps和事件绑定mapDispatchToProps),再接受一个参数(将要绑定的组件自己):
mapStateToProps:构建好Redux系统的时候,它会被自动初始化,可是你的React组件并不知道它的存在,所以你须要分拣出你须要的Redux状态,因此你须要绑定一个函数,它的参数是state,简单返回你关心的几个值。
mapDispatchToProps:声明好的action做为回调,也能够被注入到组件里,就是经过这个函数,它的参数是dispatch,经过redux的辅助方法bindActionCreator绑定全部action以及参数的dispatch,就能够做为属性在组件里面做为函数简单使用了,不须要手动dispatch。这个mapDispatchToProps是可选的,若是不传这个参数redux会简单把dispatch做为属性注入给组件,能够手动当作store.dispatch使用。这也是为何要科里化的缘由。
--------------------------------------------------------------------------------------------------------
因此这个过程应该是这样的:
view ---> action ---> reducer ---> store(state) ---> view
若是放入一个web app中,
都是函数式编程里的设计模式的东西,只是换了个马甲。
先了解下MVP模式:[Android Module] 03 - Software Design and Architecture
Presenter的角色就是:从View收集loadData这样的请求,而后交由Model的一个具体对应的函数去执行。
React 组件 API。咱们将讲解如下7个方法:
例子:设置状态:setState
<body> <div id="message" align="center"></div> <script type="text/babel"> var Counter = React.createClass({
getInitialState: function () { return { clickCount: 0 }; },
handleClick: function () { this.setState( function(state) { return {clickCount: state.clickCount + 1}; } ); },
render: function () { return (<h2 onClick={this.handleClick}>点我!点击次数为: {this.state.clickCount}</h2>); }
});
ReactDOM.render( <Counter />, document.getElementById('message') );
</script> </body>
组件的生命周期可分红三个状态:
生命周期的方法:
componentWillMount 在渲染前调用,在客户端也在服务端。
componentDidMount : 在第一次渲染后调用,只在客户端。以后组件已经生成了对应的DOM结构,能够经过this.getDOMNode()来进行访问。 若是你想和其余JavaScript框架一块儿使用,能够在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操做(防止异部操做阻塞UI)。
componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。 能够在你确认不须要更新组件时使用。
componentWillUpdate在组件接收到新的props或者state但尚未render时被调用。在初始化时不会被调用。
componentDidUpdate 在组件完成更新后当即调用。在初始化时不会被调用。
componentWillUnmount在组件从 DOM 中移除的时候马上被调用。
1. 在输入框值发生变化时咱们能够更新 state。
var HelloMessage = React.createClass({
getInitialState: function() { return {value: 'Hello Runoob!'}; },
------------------------------------------------------ handleChange: function(event) { this.setState({value: event.target.value}); },
------------------------------------------------------ render: function() { var value = this.state.value; return <div> <input type="text" value={value} onChange={this.handleChange} /> // 监听到value发生了变化,触发handleChange. <h4>{value}</h4> </div>; } });
ReactDOM.render( <HelloMessage />, document.getElementById('example') );
2. 在子组件上使用表单。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>菜鸟教程 React 实例</title> <script src="https://cdn.bootcss.com/react/15.4.2/react.min.js"></script> <script src="https://cdn.bootcss.com/react/15.4.2/react-dom.min.js"></script> <script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.min.js"></script> </head> <body> <div id="example"></div>
<script type="text/babel">
var Content = React.createClass({ render: function() { return <div> <input type="text" value={this.props.myDataProp} onChange={this.props.updateStateProp} /> <h4>{this.props.myDataProp}</h4> </div>; } });
-- 以上是子组件 --
======================================================================
-- 如下是父组件 --
var HelloMessage = React.createClass({
getInitialState: function() { return {value: 'Hello Runoob!'}; },
---------------------------------------------------------------------- handleChange: function(event) { this.setState({value: event.target.value}); },
---------------------------------------------------------------------- render: function() { var value = this.state.value; return <div> <Content myDataProp = {value} updateStateProp = {this.handleChange}>
</Content> </div>; } });
ReactDOM.render( <HelloMessage />, document.getElementById('example') );
</script> </body> </html>
1. 经过 onClick 事件来修改数据:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>菜鸟教程 React 实例</title> <script src="https://cdn.bootcss.com/react/15.4.2/react.min.js"></script> <script src="https://cdn.bootcss.com/react/15.4.2/react-dom.min.js"></script> <script src="https://cdn.bootcss.com/babel-standalone/6.22.1/babel.min.js"></script> </head>
<body> <div id="example"></div> <script type="text/babel">
------------------------------------------------------------------- var HelloMessage = React.createClass({ getInitialState: function() { return {value: 'Hello Runoob!'}; },
------------------------------------------------------------------- handleChange: function(event) { this.setState({value: '菜鸟教程'}) },
-------------------------------------------------------------------- render: function() { var value = this.state.value; return <div> <button onClick={this.handleChange}>点我</button> <h4>{value}</h4> </div>; } }); ReactDOM.render( <HelloMessage />, document.getElementById('example') ); </script> </body>
</html>
2. 从子组件中更新父组件的 state 时,你须要在父组件经过建立事件句柄 (handleChange) ,并做为 prop (updateStateProp) 传递到你的子组件上。
<body>
<div id="example"></div> <script type="text/babel">
var Content = React.createClass({ render: function() { return <div> <button onClick = {this.props.updateStateProp}>点我</button> <h4>{this.props.myDataProp}</h4> </div> } });
-- 以上是子组件 --
=======================================================================================
-- 如下是父组件 --
var HelloMessage = React.createClass({ getInitialState: function() { return {value: 'Hello Runoob!'}; },
--------------------------------------------------------------------------------------- handleChange: function(event) { this.setState({value: '菜鸟教程'}) },
--------------------------------------------------------------------------------------- render: function() { var value = this.state.value; return <div> <Content myDataProp = {value} updateStateProp = {this.handleChange}></Content> </div>; } });
ReactDOM.render( <HelloMessage />, document.getElementById('example') ); </script> </body>