《深入浅出React和Redux》(3) - Export & Import, 高阶组件

Export & Import

export可以导出函数、class等,有两种导出方式:

  • 默认导出(default export)
  • 命名导出(named export)
默认导出(default export)

default export不需要指定名称,但每个文件中只能有一个default export

// 导出纯值或表达式结果
export default 1;
const a = 1;
export default a;

// 导出函数
export default function(){
  ...
}

// 导出类
export default class {
  ...
};
命名导出(named export)

named export会指定导出名称,同一个文件中可以导出多个

// 声明变量的同时导出
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};
导入

导入的方式随导出方式的变化而变化

导入default export并赋予名称
export default function(){
  ...
}

import fun1 from './****.js';
导入named export

这时需要使用解构语法,还可以在导入时重命名,或者同时导入default export与named export。

...
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指定名称。

开发辅助工具

React Devtools

可以检视react组件的树形结构,以及每个节点上的内容,安装chrome插件即可使用。

Redux Devtools

可以检视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的一种模式,用于增强现有组件的功能。
简单来说,一个高阶组件就是一个函数,这个函数接受一个组件作为输入,然后返回一个新的组件作为结果,而且,返回的新组件拥有了输入组件所不具有的功能。
高阶组件的作用:

  • 重用代码,比如前面使用Redux时的容器组件部分是可以复用的;
  • 修改现有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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
react-native-redux-router是一个用于在React Native应用管理路由和状态的库。它结合了React Native、ReduxReact Navigation,提供了一种方便的方式来处理应用程序的导航和状态管理。 下面是一个简单的示例,演示了如何在React Native应用使用react-native-redux-router: 1. 首先,安装所需的依赖项。在终端运行以下命令: ```shell npm install react-native react-redux redux react-navigation react-native-router-flux --save ``` 2. 创建一个Redux store,并将其与React Native应用程序的根组件连接起来。在App.js文件,添加以下代码: ```javascript import React from 'react'; import { Provider } from 'react-redux'; import { createStore } from 'redux'; import rootReducer from './reducers'; import AppNavigator from './navigation/AppNavigator'; const store = createStore(rootReducer); export default function App() { return ( <Provider store={store}> <AppNavigator /> </Provider> ); } ``` 3. 创建一个导航器组件,并定义应用程序的导航结构。在navigation/AppNavigator.js文件,添加以下代码: ```javascript import { createAppContainer } from 'react-navigation'; import { createStackNavigator } from 'react-navigation-stack'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { Actions } from 'react-native-router-flux'; import HomeScreen from '../screens/HomeScreen'; import DetailsScreen from '../screens/DetailsScreen'; const MainNavigator = createStackNavigator({ Home: { screen: HomeScreen }, Details: { screen: DetailsScreen }, }); const AppNavigator = createAppContainer(MainNavigator); const mapStateToProps = state => ({ // 将Redux状态映射到导航器组件的props }); const mapDispatchToProps = dispatch => bindActionCreators(Actions, dispatch); export default connect(mapStateToProps, mapDispatchToProps)(AppNavigator); ``` 4. 创建屏幕组件,并在其使用导航和Redux状态。在screens/HomeScreen.js文件,添加以下代码: ```javascript import React from 'react'; import { View, Text, Button } from 'react-native'; import { Actions } from 'react-native-router-flux'; const HomeScreen = () => { return ( <View> <Text>Welcome to the Home Screen!</Text> <Button title="Go to Details" onPress={() => Actions.details()} /> </View> ); } export default HomeScreen; ``` 5. 创建其他屏幕组件,并在其使用导航和Redux状态。在screens/DetailsScreen.js文件,添加以下代码: ```javascript import React from 'react'; import { View, Text, Button } from 'react-native'; import { Actions } from 'react-native-router-flux'; const DetailsScreen = () => { return ( <View> <Text>Welcome to the Details Screen!</Text> <Button title="Go back" onPress={() => Actions.pop()} /> </View> ); } export default DetailsScreen; ``` 这是一个简单的示例,演示了如何在React Native应用使用react-native-redux-router来管理路由和状态。你可以根据自己的需求进行扩展和定制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值