1. 基礎實例 說明: (1).react.js:React 的核心庫。 (2).react-dom.js:提供與 DOM 相關的功能。 (3).Browser.js:將 JSX 語法轉為 JavaScript 語法。這一步很消耗時間,實際上線的時候,應該將它放到伺服器完成,操作如下: $ babe ...
1. 基礎實例
<!DOCTYPE html> <html> <head> <script src="../build/react.js"></script> <script src="../build/react-dom.js"></script> <script src="../build/browser.min.js"></script> </head> <body> <div id="example"></div> <script type="text/babel"> ReactDOM.render( <h1>Hello, world!</h1>, document.getElementById('example') ); </script> </body> </html>
說明:
(1).react.js:React 的核心庫。
(2).react-dom.js:提供與 DOM 相關的功能。
(3).Browser.js:將 JSX 語法轉為 JavaScript 語法。這一步很消耗時間,實際上線的時候,應該將它放到伺服器完成,操作如下:
$ babel src --out-dir build
將 src 子目錄的 js 文件進行語法轉換,轉碼後的文件全部放在 build 子目錄。
(4).text/babel:凡是使用 JSX 的地方,都要加上 type="text/babel"。
2. ReactDOM.render()
用於將模板轉為 HTML 語言,並插入指定的 DOM 節點。
ReactDOM.render( <h1>Hello, world!</h1>, document.getElementById('example') );
3. JSX 允許直接在模板插入 JavaScript 變數。如果這個變數是一個數組,則會展開這個數組的所有成員
var arr = [ <h1>Hello world!</h1>, <h2>React is awesome</h2>, ]; ReactDOM.render( <div>{arr}</div>, document.getElementById('example') );
4. React.createClass()
生成一個組件類。
5. class 屬性需要寫成 className ,for 屬性需要寫成 htmlFor ,這是因為 class 和 for 是 JavaScript 的保留字。
6. React.Children.map()
用來遍歷子節點,而不用擔心 this.props.children 的數據類型是 undefined 、object 、array。
this.props.children 的值有三種可能:
數據類型undefined:當前組件沒有子節點;
數據類型object:有一個子節點;
數據類型array: 有多個子節點。
var NotesList = React.createClass({ render: function() { return ( <ol> { React.Children.map(this.props.children, function (child) { return <li>{child}</li>; }) } </ol> ); } }); ReactDOM.render( <NotesList> <span>hello</span> <span>world</span> </NotesList>, document.body );
姊妹屬性還有:
React.Children.map :遍歷,返回對象
React.Children.forEach :遍歷,不返回對象
React.Children.count :返回 children 當中的組件總數
React.Children.only :返回 children 中僅有的子級。否則拋出異常
7. 組件類的 PropTypes 屬性,就是用來驗證組件實例的屬性是否符合要求
var MyTitle = React.createClass({ propTypes: { title: React.PropTypes.string.isRequired,//只接受string類型的,且必須傳 }, render: function() { return <h1> {this.props.title} </h1>; } });
姊妹屬性:
React.PropTypes.array React.PropTypes.bool React.PropTypes.func React.PropTypes.number React.PropTypes.object React.PropTypes.string React.PropTypes.node // 所有可以被渲染的對象:數字,字元串,DOM 元素或包含這些類型的數組。 React.PropTypes.element // React 元素 React.PropTypes.instanceOf(Message) // 用 JS 的 instanceof 操作符聲明 prop 為類的實例 React.PropTypes.oneOf(['News', 'Photos']) // 用 enum枚舉 來限制 prop 只接受指定的值。 React.PropTypes.oneOfType([React.PropTypes.string,React.PropTypes.number,React.PropTypes.instanceOf(Message)]) // 指定的多個對象類型中的一個 React.PropTypes.arrayOf(React.PropTypes.number) // 指定類型組成的數組(如只接受數字組成的數組) React.PropTypes.objectOf(React.PropTypes.number) // 指定類型的屬性構成的對象(如只接受數字組成的對象) React.PropTypes.shape({color: React.PropTypes.string,fontSize: React.PropTypes.number}) // 特定形狀參數的對象(字元串顏色,數字字體) 以後任意類型加上 'isRequired' 來使 prop 不可空。 React.PropTypes.func.isRequired React.PropTypes.any.isRequired //不可空的任意類型
8. getDefaultProps()設置組件屬性預設值
var MyTitle = React.createClass({ getDefaultProps : function () { return { title : 'Hello World'//沒傳遞就用預設值 }; }, render: function() { return <h1> {this.props.title} </h1>; } }); ReactDOM.render( <MyTitle />, document.body );
9. ref 獲取真實DOM
React組件生成的是虛擬DOM,只有插入到頁面中後才能變成真實的DOM。
任何DOM變動,都先在虛擬DOM上發生,然後再將實際發生變動的部分,反映在真實 DOM上,這種演算法叫做 DOM diff ,它可以極大提高網頁的性能表現。
但是,有時需要從組件獲取真實 DOM 的節點,這時就要用到 ref 屬性。
var MyComponent = React.createClass({ handleClick: function() { this.refs.myTextInput.focus();// this.refs.myTextInput 獲取真實的Input DOM }, render: function() { return ( <div> <input type="text" ref="myTextInput" /> <input type="button" value="Focus the text input" onClick={this.handleClick} /> </div> ); } }); ReactDOM.render( <MyComponent />, document.getElementById('example') );
說明:
(1) 由於真實DOM發生在虛擬DOM之後,所以this.refs.[refName]必須等到虛擬 DOM 插入文檔以後,才能使用這個屬性,否則會報錯。
(2) ref是獲取當前節點的真實DOM;this.getDOMNode()是獲取真個組件的真實DOM;兩者都必須要在組件載入完成後使用。
10. React 事件
剪貼板事件:
onCopy
onCut
onPaste
鍵盤事件:
onKeyDown
onKeyPress
onKeyUp
滑鼠事件:
onClick
onDoubleClick
onDrag
onDragEnd
onDragEnter
onDragExit
onDragLeave
onDragOver
onDragStart
onDrop
onMouseDown
onMouseEnter
onMouseLeave
onMouseMove
onMouseOut
onMouseOver
onMouseUp
onWheel :滑鼠滾輪滾動事件
觸摸事件:
onTouchCancel
onTouchEnd
onTouchMove
onTouchStart
焦點事件:
onFocus
onBlur
表單事件:
onChange
onInput
onSubmit
UI 事件:
onScroll
事件說明參考:http://reactjs.cn/react/docs/events.html
11. this.state 和 this.props
每個React組件都是一個狀態機,一旦狀態改變(與用戶發生交互)就會重新渲染組件,這就是 this.state。
每個組件又有初始化所需要的數據,一旦初始化完成,該數據就不再變動,這就是 this.props。
var LikeButton = React.createClass({ getInitialState: function() { return {liked: false}; }, handleClick: function(event) { this.setState({liked: !this.state.liked}); }, render: function() { var text = this.state.liked ? 'like' : 'haven\'t liked'; return ( <p onClick={this.handleClick}> You {text} this. Click to toggle. </p> ); } }); ReactDOM.render( <LikeButton />, document.getElementById('example') );
12. 表單
表單包括:input、textarea、checkbox、radio、option.
監聽表單組件變化使用 onChange 事件,通過以下屬性獲取對應值:
value:表單input、textarea;
checked:表單checkbox、radio;
selected:表單option。
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> ); } }); ReactDOM.render(<Input/>, document.body);
13. 組件生命周期
生命周期三個狀態:
(1)Mouting:已插入真實 DOM
(2)Updating:正在被重新渲染
(3)Unmounting:已移出真實 DOM
三個狀態對應 5 個函數 + 2 個特殊處理:
(1)componentWillMount:初始化渲染之前調用(只在第一次渲染時調用,後續重新渲染、修改props/state 都不在調用)。
允許調用setState(),組件直接使用新的state,而不會引起第二次渲染。
(2)componentDidMount:初始化渲染之後調用(只在第一次渲染時調用,後續重新渲染、修改props/state 都不在調用)。
jQuery操作DOM(如ref、getDOMNode使用)、調用外部JS方法(通過props傳遞)等都可以在這裡操作。
(3)componentWillUpdate:修改props/state 重新渲染之前調用(第一次渲染時不調用)。
不允許調用setState(),會造成死迴圈。
(4)componentDidUpdate:修改props/state 重新渲染之後調用(第一次渲染時不調用)。
不允許調用setState(),會造成死迴圈。
jQuery操作DOM(如ref、getDOMNode使用)、調用外部JS方法(通過props傳遞)等都可以在這裡操作。
(5)componentWillUnmount:組件被移除時調用(比如在div中渲染組件1,然後再渲染組件2,此時組件1被移除)。
執行任何必要的清理,比如無效的定時器,或者清除在 componentDidMount 中創建的 DOM 元素。
(6)componentWillReceiveProps(object nextProps):修改props 重新渲染 之前調用(第一次渲染時不調用;如果props和之前一樣,也會執行)。
允許調用setState(),組件直接使用新的state,而不會引起第二次渲染。
該方法中this.props可以獲取老props,參數nextProps才表示新的props。
(7)shouldComponentUpdate:是否需要重新渲染組件。修改props/state 重新渲染之前調用(第一次渲染時不調用)。
true 表示需要重新渲染;false 表示不需要重新渲染,即不會調用後續的componentWillUpdate 和 componentDidUpdate。
優化性能的關鍵函數:該方法可以實現新老props 和 state 的比對邏輯,自定義是否重新渲染。組件較多時,可提升性能。
總結:
各個生命周期函數的先後順序:
初始化渲染階段:componentWillMount > componentDidMount
修改state 階段:shouldComponentUpdate > componentWillUpdate > componentDidUpdate
修改props 階段:componentWillReceiveProps > shouldComponentUpdate > componentWillUpdate > componentDidUpdate
舊組件卸載階段:舊組件 componentWillUnmount > 新組件生命周期
生命周期測試實例:
<!DOCTYPE html> <html> <head> <script src="../build/react.js"></script> <script src="../build/react-dom.js"></script> <script src="../build/browser.min.js"></script> </head> <body> <div id="example"></div> <script type="text/babel"> var Hello = React.createClass({ getInitialState: function () { console.log('組件1getInitialState被執行'); return { name: this.props.name }; }, componentWillMount: function() { console.log('組件1:componentWillMount'); }, componentDidMount: function() { console.log('組件1:componentDidMount'); }, componentWillUpdate: function() { console.log('組件1:componentWillUpdate'); // this.setState({name: '內部componentWillUpdate更新state'});//會造成死迴圈,一直載入組件 }, componentDidUpdate: function() { console.log('組件1:componentDidUpdate'); }, componentWillUnmount: function() { console.log('組件1:被卸載:componentWillUnmount'); }, componentWillReceiveProps: function(nextProps) { console.log('組件1:componentWillReceiveProps:老props:'+this.props.name+';新props:'+nextProps.name); }, shouldComponentUpdate: function() { console.log('組件1:shouldComponentUpdate'); return true;// true 表示需要重新渲染;false 表示不需要重新渲染,即不會調用後續的componentWillUpdate和componentDidUpdate。 }, handleClick: function(event) { console.log('修改state重新渲染組件1:'); this.setState({name: '內部更新state'}); }, render: function () { return ( <div onClick={this.handleClick}> Hello {this.state.name} </div> ); } }); var Hello2 = React.createClass({ getInitialState: function () { console.log('組件2:getInitialState被執行'); return { name: this.props.name }; }, componentWillMount: function() { console.log('組件2:componentWillMount'); }, componentDidMount: function() { console.log('組件2:componentDidMount'); }, componentWillUpdate: function() { console.log('組件2:componentWillUpdate'); }, componentDidUpdate: function() { console.log('組件2:componentDidUpdate'); }, componentWillUnmount: function() { console.log('組件2:被卸載:componentWillUnmount'); }, componentWillReceiveProps: function(nextProps) { console.log('組件2:componentWillReceiveProps:老props:'+this.props.name+';新props:'+nextProps.name); }, shouldComponentUpdate: function() { console.log('組件2:shouldComponentUpdate'); return true; }, render: function () { return ( <div> Hello {this.state.name} </div> ); } }); ReactDOM.render( <Hello name="world"/>, document.getElementById('example') ); setTimeout(function(){ console.log('修改props重新渲染組件1:'); ReactDOM.render( <Hello name="world2"/>, document.getElementById('example') ); }, 3000) setTimeout(function(){ console.log('初始化渲染新組件2:'); ReactDOM.render( <Hello2 name="組件2 world2"/>, document.getElementById('example') ); }, 6000) </script> </body> </html>
14. React組件樣式
React採用行內樣式,它接受的必須是一個對象,行如:
style={{display:'none'}}
第一重大括弧表示這是 JavaScript 語法,第二重大括弧表示樣式對象。
說明:
(1)React 行內樣式採用駝峰形成,且不支持CSS中的'-'形式表示,如z-index 需寫成 zIndex。
(2)瀏覽器首碼的樣式(如-webkit-transition),首字母必須大寫,但是ms 開頭的例外。
var divStyle = { color: 'white', zIndex: 1000, paddingTop:"10px", backgroundImage: 'url(' + imgUrl + ')', WebkitTransition: 'all', // 註意這裡的首字母'W'是大寫 msTransition: 'all' // 'ms'是唯一一個首字母需要小寫的瀏覽器首碼 }; React.render(<div style={divStyle}>Hello World!</div>, mountNode);
15. Ajax請求
在實際項目中,我們通常是只把React 用於DOM渲染,而Ajax請求和邏輯判斷放在外部JS中。
如果想在React組件中調用Ajax,可以在 componentDidMount 方法中發起 Ajax 請求,等到請求成功,再用 this.setState 方法重新渲染 UI。
var UserGist = React.createClass({ getInitialState: function() { return { username: '', lastGistUrl: '' }; }, componentDidMount: function() { $.get(this.props.source, function(result) { var lastGist = result[0]; if (this.isMounted()) { this.setState({ username: lastGist.owner.login, lastGistUrl: lastGist.html_url }); } }.bind(this)); }, render: function() { return ( <div> {this.state.username}'s last gist is <a href={this.state.lastGistUrl}>here</a>. </div> ); } }); ReactDOM.render( <UserGist source="https://api.github.com/users/octocat/gists" />, document.body );
16. getInitialState()
初始化渲染之前調用(只在第一次渲染時調用,後續重新渲染、修改props/state 都不再調用)。
所以 getInitialState 中使用props 賦值時,後續重新渲染組件,state 的值將不會被新 props 覆蓋。
getInitialState 的執行早於生命周期中的其他方法。
17. getDOMNode()
獲取 React 組件的 DOM 結構。一般我們會在 componentDidMount 、componentDidUpdate 中使用,用於調用調用第三JS組件(因為第三JS組件都需要DOM結構)。
參考:http://blog.csdn.net/lihongxun945/article/details/46640225
整理自:http://www.ruanyifeng.com/blog/2015/03/react.html