React Native实践React Native开发经验集React.js

从react-navigation转react-router

2018-03-22  本文已影响723人  羽纱

这不是一篇路由入门文章,需要熟悉react-navigation,并且对react-router有基本了解。该文章主要是做两者路由的对比,让习惯使用react-navigation的开发者更好的使用react-router。
还没了解过react-router的建议在官网:react-router里过一遍文档。

react-navigation和react-router的对比:

const AppNavigator = StackNavigator({
    mainTab: {
        screen: MainTabNaivigator,
        navigationOptions: ({navigation}) => ({
            header: MainTabBarHeader,
        }),
    },
    .....
    screenOne: {
        screen: ScreenOne,
        navigationOptions: ({navigation}) => ({
            header: null
        })
    },
    screenTwo: {
        screen: ScreenTwo,
        navigationOptions: ({navigation}) => ({
            title: 'test'
        })
    },
}, {
    headerMode: 'screen',
    navigationOptions: NavigationHeader,
})

react-router:

<Root>
    <Top>
        <TopRow>
            <Route
                path={`${this.props.match.path}/Login`}
                children={({match}) => (
                    <TopItem selected={match ? true : false} onClick={() => this.props.history.push(`${this.props.match.path}/Login`)}>登录</TopItem>
                )}
            />
            <TopText>|</TopText>
            <Route
                path={`${this.props.match.path}/Register`}
                children={({match}) => (
                    <TopItem selected={match ? true : false} onClick={() => this.props.history.push(`${this.props.match.path}/Register`)}>注册</TopItem>
                )}
            />
        </TopRow>
    </Top>
    <AnimatedParent>
        <Switch location={this.props.location}>
            <Route path={`${this.props.match.path}/Login`} component={Login}/>
            <Route path={`${this.props.match.path}/Register`} component={Register}/>
        </Switch>
    </AnimatedParent>
</Root>

react-routerRoute相当于在StackNavigator定义的screen,可以看出Route并没有规则整齐的摆放在某一处,而是在需要使用的地方使用即可。同StackNavigatorRoute必须是Router的子标签才能使用,文章后面会详细介绍。


react-navigation与react-router的原理解析:

从上部分贴出的示例代码可以看出,react-routerreact-navigation的使用风格有很大的不同,其实它们的原理也不尽相同。
react-navigation原理:
通过createNavigationContainer来创建导航容器,导航容器管理着自己的state,可以通过navigation属性dispatch各种Action(例如:BACK,PUSH,RESET等),然后处理action得到新的state,从而管理着整个导航状态,再使用NavigationViews来解析state并渲染出来。
因此react-navigation提供的StackNavigatorTabbarNavigatorDrawerNavigator,它不仅管理着路由的状态树,还负责状态树按需渲染出来,提供手势及动画效果.因此它不仅依赖react,还极其依赖react-native提供的各种组件以及动画。
react-router原理:
react-router的思想是一切皆为组件,使用Route就和使用div一样的,Router管理着historyhistory就相当于react-navigation的state,所有的Route必须是Router的子标签,history里拥有着路由栈和当前路由位置(location)等信息,通过context,可以在Route的组件内获取到location,然后匹配location和当前Routepath,如果匹配成功就会拥有match属性,并且Route会被渲染出来,没有匹配成功则渲染null
react-router的原理使我们使用它和使用React组件一样简单,并且它只依赖react,能在react-native中使用。


react-router实践

<BrowserRouter>
    <App/>
</BrowserRouter>

这与react-navigation放在外层一样:

<AppNavigator
    navigation={addNavigationHelpers({
        dispatch: this.props.dispatch,
        state: this.props.nav,
    })}
/>
const App = () => (
  <BrowserRouter>
    {/* here's a div */}
    <div>
      {/* here's a Route */}
      <Route path="/tacos" component={Tacos}/>
    </div>
  </BrowserRouter>
)

// when the url matches `/tacos` this component renders
const Tacos  = ({ match }) => (
  // here's a nested div
  <div>
    {/* here's a nested Route,
        match.url helps us make a relative path */}
    <Route
      path={match.url + '/carnitas'}
      component={Carnitas}
    />
  </div>
)

react-navigation中,navigation必须传递到子navigator中才能嵌套,所以有两种方式,第一种,直接在configscreen里写navigator

const AppNavigator = StackNavigator({
    mainTab: {
        screen: MainTabNaivigator,
        navigationOptions: ({navigation}) => ({
            header: MainTabBarHeader,
        }),
    },
    ...
})

第二种就是主动把导航容器的navigation传入子导航完成嵌套(如果不懂可以移步我的另一篇文章:react-navigation路由篇之StackRouter)。

<Route path='/Login/:name/:password' component={Login}/>
...
<Link to='/Login/yusha/123'/>
...
class Login extends React.Component {
  ...
  this.props.match.params.name
  ...
}

另外一种传参方式是通过location来传,这种参数不会在url中展示出来:

<Route path='/Login' component={Login}/>
...
<Link 
  to={
    path: '/Login'
    state: {
      name: 'yusha',
      password: '123',
    }
  }
/>
...
class Login extends React.Component {
  ...
  this.props.location.state.name
  ...
}

react-router通过location来传参就类似于react-navigation通过this.props.navigation.navigate(routename, params),然后在this.props.navigation.state.params中获取一样。

//push 、replace、goBack等
this.props.history.push('/Login', {name: 'yusha', password:'123'})

<Link>相当于push<Redirect>相当于replacehistory的路由跳转的方法是不是与react-navigation中的this.props.navigation.navigate(routename, params)很像?

render() {
  const test = '123'
  return (
    ...
    <Route 
      path='routePath' 
      render=({match, location, history}) => <CustomComponent match location history test/>)
    />
    ...
  )
}

之前反复提及过,Route只有在匹配上path时才会渲染组件,否则渲染null,那要是我想路由没有匹配时也渲染呢?这时可以使用children

<TopRow>
    <Route
        path={`${this.props.match.path}/Login`}
        children={({match}) => (
            <TopItem selected={match ? true : false} onClick={() => this.props.history.push(`${this.props.match.path}/Login`)}>登录</TopItem>
        )}
    />
    <TopText>|</TopText>
    <Route
        path={`${this.props.match.path}/Register`}
        children={({match}) => (
            <TopItem selected={match ? true : false} onClick={() => this.props.history.push(`${this.props.match.path}/Register`)}>注册</TopItem>
        )}
    />
</TopRow>

注意:无论是componentrender、还是children,都会传入history, match, location这三个属性,componetrender在路由没有匹配上时渲染nullchildren在路由没有匹配上时,正常渲染,不过matchnull。因此children经常用于指示器上。

<Route path='/Login' component={Login}/>
...
class Login extends React.Component {
  componentWillReceiveProps(newProps) {
    //路由发生改变时
    console.log(this.props.location.pathname === newProps.location.pathname)  //为false
    console.log(this.props.history.location.pathname === newProps.history.location.pathname) //为true
  }
}

3、区分this.props.match.paththis.props.location.pathname
this.props.match.path代表的是当前组件路由匹配结果,match可能为空。this.props.location.pathname代表当前App路由位置。
4、区分this.props.match.paththis.porps.match.url
url是URL的匹配部分,pathRoute中定义的path

image.png

react-router参考文献

上一篇下一篇

猜你喜欢

热点阅读