react不是一個完整的mvc,mvvm框架。javascript
react跟web components 不衝突 背景原理:基於React進行開發時全部的DOM構造都是經過虛擬DOM進行,每當數據變化時,React都會從新構建整個DOM樹,而後React將當前整個DOM樹和上一次的DOM樹進行對比,獲得DOM結構的區別,而後僅僅將須要變化的部分進行實際的瀏覽器DOM更新css
react的特色就是‘輕’html
組件化的開發思路java
應用場景:複雜場景下的高性能 重用組件庫,組件組合react
ReactDOM.render()是React最基本方法 ,用於將模版轉爲HTML語言,並插入指定的DOM節點。webpack
React.createClass()方法 就用於生成一個組件類 每一個組件類都必須有本身的 render: 方法,用於輸出組件。git
注意:1 組件類第一個字母大寫 2 組件類只能包含一個頂層標籤 如用<div> 包裹github
<HelloMessage name="John"> 組建的屬性能夠在 組件類的 this.props 對象上獲取,this.props.name能夠獲取到web
this.props.children 表示此組件的全部子節點 三種結果:1 沒有子節點 undefined 2 有一個子節點 object 3 有多個子節點 arrayajax
React.Children.map() 遍歷子節點
組件類的PropTypes 屬性,用來驗證組件實例的屬性是否符合要求
propTypes:{title:React.PropTypes.string.isRequired,}
getDefaultProps 方法用來設置組件屬性的默認值 getDefaultProps:function(){return{title:'Hello World'};}
ref屬性 能夠從組件中獲取真實DOM節點 父組件引用子組件
this.refs.[name] 返回真實的DOM節點 須要等到click事件後調用
var MyComponent = React.createClass({
handleClick:function(){
this.refs.myTextInput.focus();
},
render:function(){
return(
<div>
<input type="text" ref=」myTextInput「 />
<input type = "button" value="Focus the text input" onClick = {this.handleClick} />
)
}
})
組件中getInitialState 方法用於定義初始化狀態(對象),能夠經過this.state屬性讀取。
var Input = React.createClass({
getInitialState: function() {
return {value: 'Hello!'};
},
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} />
<p>{value}</p>
</div>
);
}
});
this.setState方法就修改狀態值,每次修改後 自動調用this.render 方法,再次渲染組件。
this.props 表示那些一旦定義 就再也不改變的特性;
this.state 是會隨着用戶互動而產生改變的
上面代碼中,文本輸入框的值,不能用 this.props.value
讀取,而要定義一個 onChange
事件的回調函數,經過 event.target.value
讀取用戶輸入的值。textarea
元素、select
元素、radio
元素都屬於這種狀況
引入解析jsx的文件 <script src='http://cdnjs.cloudflare.com/ajax/libs/react/0.13.3/JSXTransformer.js'></script> type=''text/javascript"
reactComponent 是指建立的dom節點
react component lifecycle的生命週期:
1 Mounted --- React.renderComponent() React Components被render解析生成對應的DOM節點 並被插入瀏覽器的DOM結構的一個過程
componentWillMount 前被調用 --> render --> componentDidMount 後被調用
getDefaultProps()
getInitialState() 初始化
2 Update --- setState() / setProps() 至render() 一個mounted的ReactComponents被從新render的過程
componentWillUpdate / componentDidUpdate / shouldComponentUpdate /componentWillReceiveProps
3 Unmounted --- React.unmountAndReleaseReactRootNode() 一個mounted的React Components對應的DOM節點 被從DOM結構中移除的這樣一個過程
componentWillUnmount
總結:每個狀態 react都封裝了對應的hock函數
組件的生命週期:初始化——運行中——銷燬
初始化:可以使用的鉤子
1 getDefaultProps 只調用一次,實例之間共享引用
2 getInitialState 初始化每一個實例特有的狀態,都須要調用
3 componentWillMount render以前最後一次修改狀態
4 render 只能訪問this.props和this.state 不容許修改狀態和DOM輸出
5 componentDidMount 渲染完成以後觸發,可對dom進行操做。
運行中:
1 componentWillReceiveProps 父組件修改屬性觸發,能夠修改新屬性,修改狀態
2 shouldComponentUpdate 返回faulse 會阻止render調用
3 componentWillUpdate 不能修改屬性和狀態
4 render 只能訪問this.props 和 this.state,不容許修改狀態和DOM輸出
5 componentDidUpdate 能夠修改DOM
銷燬:
componentWillUnmount
屬性 組件本身不能修改屬性,能夠從父組件獲取屬性,父組件也能夠修改它的屬性,他也能夠修改子組件的屬性 :自己具備的,屬性的四種用方式:
1 <HelloWorld name=? /> 出入鍵值對 "字符創" 「item」
2 {「time」}{123}數字、字符串、等 var props={one:'123',two:321} <HeeloWorld{...props}/> {...props}展開對象的方式,取到的是值;{props}此方法取到的是對象
3 {【1,2,3】}數組
4 {變量}
狀態 只和本身相關 與父組件子組件都不相關,有本身維護 :事物所處的情況,不斷變化的
狀態用法:
1 getInitialState:初始化每一個實例特有的狀態
2 setState:更新組件狀態
setState-----diff-----dom
區分:組件在運行中須要修改的數據就是 狀態。
極客react
非dom節點:
一、 dangerouslySetInnerHTML = {rawHTML}
var rawHTML = {__html:"<h1>i'm inner HTML"}
React.render(<div style={style} dangerouslySetInnerHTML={rawHTML}></div>, )
二、ref
三、key 列表類相同的節點 li 必定要加上key值 <li key='1'></li><li key='2'></li>
事件用法:組件(1,React自有方法:render 、componentWillUpdate、componentDidMount
2. 用戶定義方法:handleClick、handleChange、handleMouseover)
綁定事件處理函數:
觸摸:onTouchCancel
onTouchEnd
onTouchMove
onTouchStart
鍵盤:onKeyDown
onKeyPress
onKeyUp
剪切:onCopy
onCut
onPaste
表單:onChange
onInput
onSubmit
焦點:onFocus
onBlur
UI元素:onScroll
滾動:onWheel
鼠標:onDrop/onDrag/onDragEnd/onDragEnter/onDragExit/onDragLeave/onDragOver/onDragStart
onClick/onContextMenu/onDoubleClick/onMouseDown/onMouseEnter/onMouseLeave/onMouseLeave/onMouseMove/onMouseOut/onMouseOver/onMouseUp
事件對象的屬性:
事件和狀態關聯:
handleChange:function(e){this.setState({inputText:e.target.value})}
組件協同:
1 組件嵌套: 父子關係 父組件-屬性-》子組件;子組件-委託(觸發事件)-》父組件
2 mixin:React雙向綁定Minxin
組件要可控:符合react的數據流;數據存儲在state中,便於使用;
表單元素:
<label htmlFor="name">對應相應的input的id</label>
<input><textarea><select><option></option></select>
事件處理函數複用:
一、bind複用:
handleChange:function(name,event){....}
{this.handleChange.bind(this,'input')}
二、name複用:
handleChange:function(event){var name=event.target.name}
{this.handleChange}
React性能調優:
提升性能的方式:虛擬DOM,diff算法,將dom操做減小到最小,可是
問題1:父組件更新默認出發全部子組件更新;解決方法:子組件覆蓋shouldComponentUpdate方法,返回true,觸發更新流程,生成新的虛擬DOM節點與以前的進行比較,不一樣則進行操做;返回false,自行解決是否更新。
問題2:列表類型的組件默認更新方式比較複雜;解決方法:給列表中的組件添加key屬性
性能調優:分析性能熱點
控制檯輸入React.addons.Perf.start()--->進行一次操做---->React.addons.Perf.stop() ;完成後臺記錄消耗時間
查看記錄結果:React.addons.Perf.printInclusive();
如何解決性能問題:1;PureRenderMixin判斷是否須要進入更新流程,本質上就是判斷狀態和屬性是否改變(只能處理原始值,不能處理對象)
在shouldComponentUpdate(nextProps,nextStates)內判斷!shallowEqual(this.props,nextProps)||!shallowEqual(this.state,nextState);
2;不可變插件Immutability Helpers,實現js不可變對象
基本語法:update(obj,cmd)
組件嵌套:
鉤子函數:
初始化:getDefaultProps 只調用一次
getInitialState
componentWillMount 渲染以前最後一次修改狀態this.setState({}),觸發render()函數;
render
componentDidMount 操做或修改真正的dom
運行中:componentWillReceiveProps 父組件修改屬性以前觸發,此函數能夠修改新屬性、修改狀態
shouldComponentUpdate 返回false,根據須要使用
componentWillUpdate :不能修改屬性和狀態
render:只能訪問this.props和this.state,不能修改
componentDidUpdate :能夠修改dom
銷燬:componentwillUnmount 在刪除組件以前進行清理操做,好比計時器和事件監聽器,必須手動清理。方法1.在子組件中componentwillUnmount:function(){} 方法2:在子組件的handle函數中,調用:React.unmountComponentAtNode(document.getElementsByTagName('body')[0]);//傳入的必須是裝載入的節點。
React.findDOMNode()
react添加css動畫:
var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup; 引入react-addons-t
調用:return(<ReactCSSTransitionGroup transitionName="example">{items}</ReactCSSTransitionGroup>)
react添加js動畫:
componentDidUpdate:function(){if(this.props.position){setTimeout(this.resolveSetTimeout,this.props.timeoutMs);}},
render:function(){var divStyle={marginLeft:this.state.position};return <div style={divStyle}>this will animate!</div>}})
React.render(<Positioner></positioner>,document.body);
React.render(<Positioner position={100} timeout={10}></Positioner>,document.body);第二次調用,改變屬性值props,觸發componentDIdUpdate();從而達到動畫效果
項目實戰:
1.分析目標-肯定開發順序:頁面上有組件->組件能正常顯示內容->內容的樣式正確->設置項能夠正常工做->交互功能正常
在jsx中使用循環,通常會用到Array.prototype.map
class Hello extends React.Component{ render(){ const arr = ['a','b','c']; return ( <div> {arr.map((item,index) => { return <p key={index}> this is {item}</p> })} </div> ) } }
參考連接:http://www.imooc.com/article/14500
代碼分離:
page層 ./app/containers/Hello/index.jsx
subpage層 ./app/containers/Hello/subpage/...jsx
component層 ./app/components/... 把多個頁面均可能用到的功能,封裝到一個組件中,放到此目錄下。
數據傳遞&數據變化
props:通常只用做父組件給子組件傳遞數據用,不能被自身修改。
每一個頁面引用Header時,設置獨自的title屬性值,<Header title='Hello頁面'/>;而在子組件中這樣取到 render(){return(<p>{this.props.title}</p>)}
state:自身組件狀態發生變化,constructor(props,context){super(props,context);this.state = {now:Date.now()}} render(){return (<div><p>hello world {this.state.now}</p></div>)}}
智能組件&木偶組件
智能組件:./app/containers 簡稱「頁面」,只對數據負責,只需獲取數據、定義好數據操做的相關函數,而後將這些數據、函數直接傳遞給具體的實現組件。
木偶組件:作一些展現的工做,展現給用戶。 ./app/components/...
性能檢測優化:參考https://github.com/wangfupeng1988/react-simple-o2o-demo/tree/getready-redux-width-react 本地切換到對應的分支
1安裝react的性能檢測工具npm install react-addons-perf --save 在./app/index.jsx中import Perf from 'react-addons-perf' if(__DEV__){window.Perf = Perf}
使用:Perf.start()開始檢測,Perf.stop中止檢測,Perf.printWasted()便可打印出浪費性能的組件列表。
2安裝react的優化插件 PureRenderMixin,npm install react-addons-pure-render-mixin --save
使用:在constructor(props,context){super(props,context);this.shouldComponentUpdate = PureRenderMixin.shouldComponentUpdate.bind(this);}} 重寫組件shouldComponentUpdate函數,在每次更新以前判斷props和state,若是有變化返回true。
3 Immutable.js優化:使用此來處理數據,實現js中不可變數據的概念。適用於數據結構層次很深(obj.x.y.a.b=10)其定義了新的語法,不輕易使用。
React-router
安裝 npm install react-route --save
1 建立子頁面./app/containers/App.jsx 全部頁面的外殼 ./app/containers/Home等主頁、列表頁、詳情頁
2 配置router 建立./app/router/routerMap.jsx 文件
class RouteMap extends React.Component{ updateHandle(){ //每次router變化以後都會觸發 } render(){ return ( <Router history={this.props.history} onUpdate={this.updateHandle.bind(this)}> <Route path='./' component={App}> <IndexRoute component={Home}/> <Route path='list' component={list}/> <Route path='detail/:id' component={Detail}/> //id表示參數 <Route path="*" component={NotFound}/> </Route> //route能夠嵌套 </Route> ) } }
3 使用Route
./app/index.jsx
import React from 'react' import {render} from 'react-dom' import {hashHistory} from 'react-router' import RouteMap from './router/routeMap' render( <RouteMap history={hashHistory}/>, //hashHistory規定hash來表示router localhost:8080/#/list document.getElementById('root') )
頁面跳轉
1 <link to='/list'>to list </link>
2 js跳轉
return(<ul>
{arr.map((item,index) => {
return <li key={index} onClick={this.clickHandle.bind(this,item)}>js jump to {item} </li>})}
</ul>)}
clickHandle(value){
hashHistory.push('/detail/' + value)
}}
性能優化--靜態資源懶加載 huge-apps
他將react-router自己和webpack的require.ensure結合起來,解決此問題。