Reactjavascript
We built React to solve one problem: building large applications with data that changes over time.css
核心html
普通的現代構建管道一般包括java
經常使用庫概覽node
react.js:React的核心庫 react-dom.js:提供與DOM相關的操做功能 Browser.js:將JSX語法轉爲JavaScript語法(耗時)
Elements are the smallest building blocks of React apps.react
Small and Isolated pieces of code,模版即組件,組件即HTML自定義標籤,是包含了模板代碼的一種特殊的HTML標籤類型。webpack
當組件第一次渲染到DOM時,在React中稱爲掛載(mounting);當組件產生的DOM被銷燬時,在React中稱爲卸載(unmounting)。git
全部React組件都必須是純函數,並禁止修改其自身props 。在JSX回調中必須注意this的指向,提供3種方法:github
推薦第1種。箭頭函數每次渲染時都建立一個不一樣的回調。多數狀況下沒問題,然而若是這個回調被做爲prop(屬性)傳遞給下級組件,這些組件可能須要額外的重複渲染。web
setState
this.state
的地方// ok,當前值不依賴上一次的值 this.setState({name: 'Hello'}); // 提供callback方式1 this.setState((prevState, props) => { return { ...prevState, name: props.name }; }); // 或 this.setState((prevState, props) => ({ counter: prevState.counter + props.increment })); // 或 this.setState(function(prevState, props) { return { counter: prevState.counter + props.increment }; }); // 提供callback方式2 this.setState({ name: 'qwer' }, ()=>{ console.log(this.state.name); //qwer });
在狀態更新、渲染完成後,會觸發對回調函數的執行。有關信息參見:react - setState;
狀態提高(Lifting State Up)
state建立有2種:
在React中,共享state(狀態)是經過將其移動到須要它的組件的最接近的共同祖先組件來實現,使React的state成爲 「單一數據源原則」 。
在一個React應用中,對於任何可變的數據都應該循序「單一數據源」原則,依賴從上向下的數據流向。
對於UI中的錯誤,使用React開發者工具來檢查props,向上遍歷樹,直到找到負責更新狀態的組件,跟蹤到bug的源頭。
具體參見:React Developer Tools
將參數傳遞給事件處理程序
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button> <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
對於第2種方法,方法定義的形式
deleteRow(id, event) {...}
當須要從子組件中更新父組件的state時,要在父組件建立事件句柄 (handleChange) ,並做爲prop (updateStateProp) 傳遞到子組件。
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') );
綜上,對於顯式bind方式,通式以下
handleclick(要傳的參數,event){...} onClick = {this.handleclick.bind(this,要傳的參數)}
組件鉤子函數生命週期
。。。
高階組件
高階組件是一個函數,接受一個組件並返回一個新的組件
const EnhancedComponent = higherOrderComponent(WrappedComponent);
錯誤邊界
Error Boundaries 是React組件,它能夠在子組件樹的任何位置捕獲JavaScript錯誤、記錄這些錯誤,並顯示一個備用UI,而不是使整個組件樹崩潰。可是,僅能夠捕獲其子組件的錯誤,沒法捕獲其自身的錯誤。對如下狀況無能爲力:
鉤子函數:componentDidCatch(error, info)
相似JS的catch(){}方法,若是一個錯誤邊界沒法渲染錯誤信息,則錯誤會向上冒泡至最接近的錯誤邊界。
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { error: null, errorInfo: null }; } componentDidCatch(error, errorInfo) { // Catch errors in any components below and re-render with error message this.setState({ error: error, errorInfo: errorInfo }) // You can also log error messages to an error reporting service here } render() { if (this.state.errorInfo) { // Error path return ( <div> <h2>Something went wrong.</h2> <details style={{ whiteSpace: 'pre-wrap' }}> {this.state.error && this.state.error.toString()} <br /> {this.state.errorInfo.componentStack} </details> </div> ); } // Normally, just render children return this.props.children; } }
ref屬性
用來綁定到render()輸出的任何組件上,容許引用render()返回的相應的支撐實例(Backing Instance)。
簡言之,用於從組件獲取真實的DOM結點。
組件並非真實的DOM節點,而是存在於內存之中的一種數據結構,叫作虛擬DOM (virtual DOM)。只有當它插入文檔之後,纔會變成真實的DOM 。根據 React 的設計,全部的DOM變更,都先在虛擬DOM上發生,而後再將實際發生變更的部分,反映在真實DOM上,這種算法叫作 DOM diff,能夠極大提升網頁的性能表現。
場景:獲取組件new出來的實例,繞過父子組件通訊的約束,直接操做組件new出來的實例
經過ref屬性獲取到React組件new出來的真實實例,前置條件:
真實DOM結點結構 = ReactDOM.findDOMNode(組件真實實例)
this.props.children屬性
表示組件的全部子結點,其值有三種可能:
React提供工具方法:React.Children,智能處理(容錯) this.props.children。
React.Children.map(children, function[(thisArg)]) React.Children.forEach(children, function[(thisArg)]) React.Children.count(children) React.Children.only(children) React.Children.toArray(children)
條件渲染組件
To do this return null instead of its render output:從組件的render方法返回null不會影響組件生命週期方法的觸發。
function WarningBanner(props) { if (!props.warnsInfoMsg) { return null; } return ( <div className="warning"> Warning! {this.props.warnsInfoMsg} </div> ); }
模塊加載機制
CommonJS規範
// 模塊對外提供變量或函數方法 module.exports = { key: value ... }; // 引入模塊 const module = require('./Module.js');
上下文,提供經過組件樹傳遞數據的方法,在組件間共享數據,避免經過中間元素傳遞 props。
class App extends React.Component { render() { return <Toolbar theme="dark" />; } } function Toolbar(props) { // The Toolbar component must take an extra "theme" prop // and pass it to the ThemedButton. This can become painful // if every single button in the app needs to know the theme // because it would have to be passed through all components. return ( <div> <ThemedButton theme={props.theme} /> </div> ); } function ThemedButton(props) { return <Button theme={props.theme} />; }
// Context lets us pass a value deep into the component tree without explicitly threading it through every component. // Create a context for the current theme (with "light" as the default). const ThemeContext = React.createContext('light'); class App extends React.Component { render() { // Use a Provider to pass the current theme to the tree below. // Any component can read it, no matter how deep it is. // In this example, passing "dark" as the current value. return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ); } } // A component in the middle doesn't have to pass the theme down explicitly anymore. function Toolbar(props) { return ( <div> <ThemedButton /> </div> ); } function ThemedButton(props) { // Use a Consumer to read the current theme context. // React will find the closest theme Provider above and use its value. // In this example, the current theme is "dark". return ( <ThemeContext.Consumer> {theme => <Button {...props} theme={theme} />} </ThemeContext.Consumer> ); }
其中,ThemeContext 是 {Provider, Consumer} 對象
const {Provider, Consumer} = React.createContext(defaultValue); <Provider value={/* some value */}> <Consumer> {value => /* render something based on the context value */} </Consumer>
仔細體會,該方式相似發佈訂閱模式,provider生產數據,Consumer消費數據。
具體參見:Context - React;
頁面設計流程
注:不要在子組件上直接調用父組件方法。子組件應該封裝一個事件句柄,在句柄內調用回調函數。
關於肯定 UI state
具體參見:React 編程思想;
學習了下React 核心開發者出品的 React 設計思想 ,簡單總結以下:
變換(Transformation):純函數
抽象(Abstraction):函數/組件調用
組合(Composition):組合思想,而非繼承
狀態(State):不可變性,setState()
Memoization:記憶緩存
列表(Lists)
連續性(Continuations)
代數效應(Algebraic Effects):context
關於React註釋
ReactDOM.render( /*註釋 */ <h1>xxxx {/*註釋*/}</h1>, document.getElementById('root') );
關於Html與React
環境判斷
根據瀏覽器和Node環境提供的全局變量名稱來判斷當前環境:
if (typeof(window) === 'undefined') { console.log('node.js'); } else { console.log('browser'); }
關於規範
具體參見:Airbnb React/JSX Style Guide;
參考: