从navigator到react-navigation实战教程

随着react-navigation逐渐稳定,Navigator也被光荣的退休了。在React Native生态环境中需要一款可扩展且易于使用的导航组件,Navigator 自然胜任不了,这时React Native社区便孕育出了一个开源导航组件react-navigation

react-navigation的出现替代了Navigator、 Ex-Navigation等老一代的导航组件,react-navigation可以说是Navigator的加强版,不仅有Navigator的全部功能,另外还支持底部导航类似于与iOS中的UITabBarController,此外它也支持侧拉效果方式的导航类似于Android中的抽屉效果

这篇文章将向大家分享react-navigation的一些实用技巧,以及从navigator到react-navigation的一些实战经验。另外大家也可以学习与本教程配套的视频版:《全新导航器react-navigation精讲》

什么是导航器?

导航器也可以看成一个是普通的React组件,你可以通过导航器来定义你的App的导航结构。 导航器还可以渲染通用元素,例如可以配置的标题栏和选项卡栏。

在react-navigation中有以下三种类型的导航器:

  • StackNavigator: 类似于普通的Navigator,屏幕上方导航栏;
  • TabNavigator: 相当于iOS里面的TabBarController,屏幕下方的标签栏;
  • DrawerNavigator: 抽屉效果,侧边滑出;

{:height=”90%” width=”90%”}

你可以通过以上三种导航器来创建你APP,可以是其中一个也可以多个组合,这个可以根据具体的应用场景并结合每一个导航器的特性进行选择。

在开始学习三种导航器之前,我们需要先了解两个和导航关于概念:

  • Screen navigation prop(屏幕导航属性):通过navigation可以完成屏幕之间的调度操作,例如打开另一个屏幕;
  • Screen navigationoptions(屏幕导航选项): 通过navigationoptions可以定制导航器显示屏幕的方式(例如:头部标题,选项卡标签等);

导航器所支持的Props

const SomeNav = StackNavigator/TabNavigator/DrawerNavigator({
  // config
});

<SomeNav
  screenProps={xxx}
  ref={nav => { navigation = nav; }}
  onNavigationStateChange=(prevstate,newState,action)=>{

  }
/>

@全新导航器react-navigation精讲

  • ref:可以通过ref属性获取navigation
  • onNavigationStateChange(prevstate,action):顶级节点除了ref属性之外,还接受onNavigationStateChange(prevstate,action)属性,每次当导航器所管理的state发生改变时,都会回调该方法
    • prevstate:变化之前的state;
    • newState:新的state;
    • 导致state变化的action;
  • screenProps:向子屏幕传递额外的数据,子屏幕可以通过this.props.screenProps获取到该数据。

Screen Navigation Prop(屏幕的navigation Prop)

当导航器中的屏幕被打开时,它会收到一个navigation prop,navigation prop是整个导航环节的关键一员,接下来就详细讲解一下navigation的作用。

navigation包含一下功能

  • navigate:跳转到其他界面;
  • state:屏幕的当前state;
  • setParams:改变路由的params;
  • goBack:关闭当前屏幕;
  • dispatch:向路由发送一个action;

注意:一个navigation有可能没有navigate、setParams以及goBack,只有state与dispatch,所以在使用navigate时要进行判断,如果没有navigate可以使用navigation去dispatch一个新的action。如:

const {navigation,theme,selectedTab}=this.props;
const resetAction = NavigationActions.reset({
    index: 0,actions: [
        NavigationActions.navigate({
            routeName: 'HomePage',params:{
                theme:theme,selectedTab:selectedTab
            },})
    ]
})
navigation.dispatch(resetAction)

@全新导航器react-navigation精讲

使用navigate进行界面之间的跳转

  • navigate(routeName,params,action)
    • routeName:要跳转到的界面的路由名,也就是在导航其中配置的路由名;
    • params:要传递给下一个界面的参数;
    • action:如果该界面是一个navigator的话,将运行这个sub-action。
export const AppStackNavigator = StackNavigator({
    HomeScreen: {
        screen: HomeScreen
    },Page1: {
        screen: Page1
    })

class HomeScreen extends React.Component {
  render() {
    const {navigate} = this.props.navigation;

    return (
      <View>
        <Text>This is HomeScreen</Text>
        <Button
          onPress={() => navigate('Page1',{name: 'Devio'})}
          title="Go to Page1"
        />
      </View>
     )
   }
}

@全新导航器react-navigation精讲

使用state的params

可以通过this.props.state.params来获取通过setParams(),或navigation.navigate()传递的参数。

<Button
    title={params.mode === 'edit' ? '保存' : '编辑'}
    onPress={() =>
        setParams({mode: params.mode === 'edit' ? '' : 'edit'})}
/>
<Button
    title="Go To Page1"
    onPress={() => {
        navigation.navigate('Page1',{ name: 'Devio' });
    }}
/>
const {navigation} = this.props;
const {state,setParams} = navigation;
const {params} = state;
const showtext = params.mode === 'edit' ? '正在编辑' : '编辑完成';

@全新导航器react-navigation精讲

使用setParams 改变route params

  • setParams: function setParams(params)
    我们可以借助setParams来改变route params,比如,通过setParams来更新页面顶部的标题,返回按钮等;
class ProfileScreen extends React.Component {
  render() {
    const {setParams} = this.props.navigation;
    return (
      <Button
        onPress={() => setParams({name: 'Lucy'})}
        title="Set title name to 'Lucy'"
      />
     )
   }
}

@全新导航器react-navigation精讲

注意navigation.setParams改变的是当前页面的Params,如果要改变其他页面的Params可以通过NavigationActions.setParams完成,下文会讲到。

使用goBack返回到上一页面或指定页面

  • goBack: function goBack(key):我们可以借助goBack返回到上一页或者路由栈的指定页面

    • 其中key表示你要返回到页面页面标识如id-1517035332238-4,不是routeName。
    • 可以通过指定页面navigation.state.key来获得页面的标识。
    • key非必传,也可传null。


    navigation.state
    {params: {…},key: "id-1517035332238-4",routeName: "Page1"}

export default class Page1 extends React.Component {
    render() {
        const {navigation} = this.props;
        return <View style={{flex: 1,backgroundColor: "gray",}}>
            <Text style={styles.text}>欢迎来到Page1</Text>
            <Button
                title="Go Back"
                onPress={() => {
                    navigation.goBack();
                }}
            />
        </View> 
    }
}

@全新导航器react-navigation精讲

通过dispatch发送一个action

  • dispatch: function dispatch(action):给当前界面设置action,会替换原来的跳转,回退等事件。
const resetAction = NavigationActions.reset({
    index: 0,})
    ]
    })
navigation.dispatch(resetAction)

@全新导航器react-navigation精讲

Navigatie action会使用Navigate action的结果来更新当前的state。

  • routeName:字符串,必选项,在app的router里注册的导航目的地的routeName。
  • params:对象,可选项,融合进目的地route的参数。
  • actions:对象,可选项(高级),如果screen也是一个navigator,次级action可以在子router中运行。在文档中描述的任何actions都可以作为次级action。
import { NavigationActions } from 'react-navigation'

const navigateAction = NavigationActions.navigate({
  routeName: 'Profile',params: {},action: NavigationActions.navigate({ routeName: 'SubProfileRoute'})
})
this.props.navigation.dispatch(navigateAction)

@全新导航器react-navigation精讲

Reset:

Reset action删掉所有的navigation state并且使用这个actions的结果来代替。

  • index,number,必选,navigation state中route数组中激活route的index。
  • actions,array,必选项,Navigation Actions数组,将会替代navigation state。
import { NavigationActions } from 'react-navigation'

const resetAction = NavigationActions.reset({
  index: 0,actions: [
    NavigationActions.navigate({ routeName: 'Profile'})
  ]
})
this.props.navigation.dispatch(resetAction)

@全新导航器react-navigation精讲

使用场景比如进入APP首页后的splash页不在使用,这时可以使用NavigationActions.reset重置它。

index参数被用来定制化当前激活的route。举个例子:使用两个routes WelcomePage和HomePage给一个基础的stack navigation设置。为了重置route到HomePage,但是在堆栈中又存放在WelcomePage之上,你可以这么做:

import { NavigationActions } from 'react-navigation'

const resetAction = NavigationActions.reset({
    index: 1,actions: [
        NavigationActions.navigate({ routeName: 'WelcomePage'}),NavigationActions.navigate({ routeName: 'HomePage'})
    ]
});
this.props.navigation.dispatch(resetAction);

@全新导航器react-navigation精讲

Back

返回到前一个screen并且关闭当前screen.backaction creator接受一个可选的参数:

  • key:这个可以和上文中讲到的goBack的key是一个概念;
import { NavigationActions } from 'react-navigation'
const backAction = NavigationActions.back();
this.props.navigation.dispatch(backAction);

SetParams

通过SetParams我们可以修改指定页面的Params。

  • params:对象,必选参数,将会被合并到已经存在页面的Params中。
  • key:字符串,必选参数,页面的key。
import { NavigationActions } from 'react-navigation'
const setParamsAction = NavigationActions.setParams({
    params: { title: 'HomePage' },key: 'id-1517035332238-4',});

有很多小伙伴可能会问:navigation中有setParams为什么还要有NavigationActions.setParams?

我从两方面来回答一下这个问题:

  1. 在上文中讲到过navigation中有可能只有state与dispatch,这个时候如果要修改页面的Params,则只能通过NavigationActions.setParams了;
  2. 另外,navigation.setParams只能修改当前页面的Params,而NavigationActions.setParams可以修改所有页面的Params;

还有那些应用场景?

在导航器屏幕之外使用导航功能(巧用导航器的ref)

有一种场景:有的时候我们需要在导航器中所定义的屏幕之外使用导航器来做页面跳转

  • 屏幕之间的跳转是需要借助navigation来完成的;
  • 我们知道导航器中定义的屏幕可以通过const {navigation} = this.props;获取navigation
  • 那么,如果我们在非导航器中所定义的屏幕中做屏幕跳转的关键一步,就是要想法获取navigation
  • 那么,如何才能在非导航器中所定义的屏幕中获取到这个navigation呢?

下面就给大家讲解通过ref属性还获得navigation

示例看代码

import { NavigationActions } from 'react-navigation';

const AppNavigator = StackNavigator(SomeAppRouteConfigs);

class App extends React.Component {
  someEvent() {
    // call navigate for AppNavigator here:
    this. navigation && this. navigation.dispatch(
      NavigationActions.navigate({ routeName: someRouteName })
    );
  }
  render() {
    return (
      <AppNavigator ref={nav => { navigation = nav; }} />
    );
  }
}

上述代码通过导航器的顶级节点ref属性获取navigation,当上述代码AppNavigator节点被渲染时,ref会被回调这是就可以获取navigation了,需要提醒大家的是,这种用法对除StackNavigator之外的其他两种类型的导航器也是实用的哦;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom