export能夠導出函數、class等,有兩種導出方式:react
default export不須要指定名稱,但每一個文件中只能有一個default exportgit
// 導出純值或表達式結果 export default 1; const a = 1; export default a; // 導出函數 export default function(){ ... } // 導出類 export default class { ... };
named export會指定導出名稱,同一個文件中能夠導出多個github
// 聲明變量的同時導出 export let a =1; // 導出函數 export function func1(){ ... } // 統一導出 const a = 1; const obj1 = {name: 'obj1'}; export {a, obj1}; // 導出時修更名稱 const obj1 = {name: 'obj1'}; export {obj1 as newObjName};
導入的方式隨導出方式的變化而變化chrome
export default function(){ ... } import fun1 from './****.js';
這時須要使用解構語法,還能夠在導入時重命名,或者同時導入default export與named export。redux
... export {a, obj1}; // 解構導出 import {a, obj1} from './****.js'; // 導入時重命名 import {a, obj1 as newObject} from './****.js';
還可使用*所有導入,此時必須使用as指定名稱數組
export {a, obj1}; import * as name from './****.js'; // 使用 name.a name.obj1
同時導入default export與named export:瀏覽器
export default function()... export function func1()... export function func2()... import defaultFunc, * as named from './****.js';
前一部分首先導出的時default export,後面導出named export並用as指定名稱。app
能夠檢視react組件的樹形結構,以及每一個節點上的內容,安裝chrome插件便可使用。函數
能夠檢視redux數據流,記錄每一次action以及store的對應變化,能夠將store狀態跳躍到任意一個歷史狀態(時間旅行)。
安裝chrome插件後還須要一些代碼支持,由於redux devtools的工做原理是截獲全部應用中Redux Store的動做和狀態變化,因此必須經過Store Enhancer在Redux Store中加入鉤子。因此須要修改Store.js:工具
const storeEnhancers = (window && window.devToolsExtension) ? window.devToolsExtension() : (f) => f; export default createStore(reducer, {}, storeEnhancers);
這裏添加的storeEnhancers的做用就是讓redux devtools可以截獲當前應用的store狀態,安裝redux devtools後瀏覽器全局就會有window.devToolsExtension對象,但也須要作好兼容,在沒有這個工具的瀏覽器運行時,這個enhancer是一個什麼都不作的函數。
高階組件(Higher Order Component,HOC)是使用react的一種模式,用於加強現有組件的功能。
簡單來講,一個高階組件就是一個函數,這個函數接受一個組件做爲輸入,而後返回一個新的組件做爲結果,並且,返回的新組件擁有了輸入組件所不具備的功能。
高階組件的做用:
高階組件按照實現方式又能夠分爲
新組件扮演的角色是傳入參數組件的一個「代理」,在新組件的render函數中,把被包裹組件渲染出來,除了高階組件本身要作的工做,其他功能全都轉手給了被包裹的組件。
這種組織方式下,能夠用來修改被包裹組件的prop、style等。紹:
操縱prop
好比下面的addNewProps組件,能夠爲WrappedComponent添加屬性:
const addNewProps = (WrappedComponent, newProps) => { return class WrappingComponent extends React.Component { render() { return <WrappedComponent {...this.props} {...newProps} /> } } }
嚴格來講,這裏的addNewProps是一個組件工廠,但通常也直接將其看做組件。
抽取狀態
相似前面redux部分本身寫的容器組件,以及react-redux提供的connect函數生成的組件。
包裝組件
好比能夠用來組合多個react組件,或者爲被包裝的組件添加統一的樣式。
前面的addNewProps用繼承方式實現以下:
function addNewProps(WrappedComponent) { return class NewComponent extends WrappedComponent { render() { const {newProps} = this.props; this.props = {...this.props, newProps}; return super.render(); } }; }
最大的區別在於return super.render();
在代理方式下WrappedComponent經歷了一個完整的生命週期,但在繼承方式下super.render只是一個生命週期中的一個函數而已;在代理方式下產生的新組件和參數組件是兩個不一樣的組件,一次渲染,兩個組件都要經歷各自的生命週期,在繼承方式下二者合二爲一,只有一個生命週期。因此繼承方式的高階組件能夠用來操縱組件的生命週期函數,好比下面的組件經過shouldComponentUpdate控制只有useCache=false纔會從新渲染:
const cacheHOC = (WrappedComponent) => { return class NewComponent extends WrappedComponent { shouldComponentUpdate(nextProps, nextState) { return !nextProps.useCache; } } }
高階組件與原組件之間是父子關係,他們的通訊要用到props,這也就意味着高階組件有個缺點,就是原組件的props中須要包含高階組件傳遞的字段,也就是說,能不能把一個高階組件做用於某個組件X,要先看一下這個組件X是否是可以接受高階組件傳過來的props。
高階組件這種要求參數組件必須和本身有契約的方式,會爲自身的使用帶來極大的侷限。
而「以函數爲子組件」的模式就是爲了克服這種侷限而生的。
前文的addNewProps用「以函數爲子組件」實現的話,就是:
const loginUser='fake user'; class AddNewProps extends Component{ render(){ const user = loginUser; return this.props.children(user); } }
與高階組件那種組件工廠不一樣,這裏AddNewProps自己就是一個組件,經過this.props.children來調用原組件,並把值傳遞過去,原組件必須是一個函數。
AddNewProps的使用:
// 讓一個組件直接顯示user <AddNewProps> {(user)=> <div>{user}</div>} </AddNewProps> // 將user傳遞給另外一個組件 <AddNewProps> {(user)=> <Foo user={user}>} </AddNewProps> // 將user傳遞給另外一個組件,支持不一樣的prop名稱 <AddNewProps> {(user)=> <Foo anotherProp={user}> </AddNewProps>
從「以函數爲子組件」的第三個例子能夠看到,這種模式很是靈活,它徹底能夠應付prop不一樣名的狀況。做爲子組件的函數成爲了鏈接父組件與底層組件的橋樑,並且這個函數內部能夠包含各類邏輯。
《深刻淺出React和Redux》 程墨
徹底解析 JavaScript import、export