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