【React Native】学习记录(二)——路由搭建和常见的开发技巧

模拟器设置成中文

在开发过程中发现,两个模拟器都不能输入中文,所以需要配置一下。

先说一下安卓,在弹出的输入框中查看设置,设置一下对应的languages即可:
在这里插入图片描述在苹果模拟器中,跟苹果手机一样,打开设置,然后打开通用,同样设置语言:
在这里插入图片描述

路由搭建

我在这里走了弯路,去了另一个库…,路由文档入口在这:链接

sudo npm install @react-navigation/native
# 兼容expo
sudo npx expo install react-native-screens react-native-safe-area-context
# 路由跳转的本质是堆栈
sudo npm install @react-navigation/native-stack
# 我们项目中会使用到底部导航栏跳转
sudo npm install @react-navigation/bottom-tabs

我要做的东西如下:
在这里插入图片描述
大概也能猜出哪些路由了,这里说一下路由中tab页面和普通页面的搭建,关于抽屉页面,后续使用了再补上:

// router/index.js
import react from 'react';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Feather } from '@expo/vector-icons';
import { MaterialCommunityIcons } from '@expo/vector-icons';

import HabitHome from '../views/habit/home/index';
import HabitDetail from '../views/habit/detail/index';
import HabitSet from '../views/habit/set';
import DateHome from '../views/date/home/index';
import DateSet from '../views/date/set/index';


// 这里声明了底部tab页面有哪些,还配置了顶部导航栏的一些自定义按钮
const Tab = createBottomTabNavigator();

function TabStack(){
    return (
        <Tab.Navigator 
        screenOptions={{ 
          headerShown: true,
          tabBarInactiveTintColor: '#333',
          tabBarActiveTintColor: '#6528F7',
          tabBarShowLabel: true,
        }}>
            <Tab.Screen 
              name="HabitHome" 
              component={HabitHome}
              options={{
                title: '',
                tabBarLabel: '打卡',
                tabBarIcon: ({ color, size }) => (
                  <Feather name="target" color={color} size={size} />
                ),
              }} />
            <Tab.Screen 
            name="DateHome" 
            component={DateHome}
            options={{
              title: '',
              tabBarLabel: '纪念日',
              tabBarIcon: ({ color, size }) => (
                <MaterialCommunityIcons name="calendar-heart" color={color} size={size} />
              ),
            }} />
        </Tab.Navigator>
    )
}

// 将底部导航栏和非底部导航栏的页面都写在这里:
const Stack = createNativeStackNavigator();

function PageStack(){
  return (
    <Stack.Navigator>
      <Stack.Screen
          name="TabStack"
          component={TabStack}
          options={{ headerShown: false }}
      />
      <Stack.Screen name="HabitDetail" component={HabitDetail} options={{ title: '习惯详情' }} />
      <Stack.Screen 
        name="HabitSet" 
        component={HabitSet}
        options={{
          title: '添加一个习惯'
        }} />
      <Stack.Screen name="DateSet" component={DateSet} options={{ title: '设置纪念日' }} />
    </Stack.Navigator>
  )
}

export default PageStack;


接下来就是在App.js中使用了:

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { Provider } from 'react-redux'
import store from './store/index'
import  PageStack from './router/index'

function App() {
  return (
    <Provider store={store}>
      <NavigationContainer>
        <PageStack />
      </NavigationContainer>
    </Provider>
  );
}

export default App;

用的状态管理器,还是redux,像以前在普通react项目中那样使用就行(官网地址

开发技巧

  1. ScrollView适合用来显示数量不多的滚动元素。放置在ScrollView中的所有组件都会被渲染(还没滑动到下一屏幕,也是会被渲染出来),FlatList更适于长列表数据,且元素个数可以增删,和ScrollView不同的是,FlatList并不立即渲染所有元素,而是优先渲染屏幕上可见的元素。综上,如果列表太长的情况下,可以优先使用FlatList
  2. View组件类似Div组件,但是没有点击事件;
  3. 所有文字必须包含在Text组件中;
  4. Button组件在两端的机器上显示的不一样,所以为了确保样式一致性,我会使用View按钮来制作按钮;
  5. 由于View上没有点击事件,所以我借助了TouchableOpacity,而安卓机上还有一个特有的组件:TouchableNativeFeedback,做了如下封装:
import { TouchableOpacity, TouchableNativeFeedback, Platform } from 'react-native';

function CommonButton (props){
    const { onPress, children } = props;

    if(Platform.OS === 'android') {
        return (
            <TouchableNativeFeedback 
                background={TouchableNativeFeedback.Ripple('rgba(215, 187, 245, 0.5)', false)}
                onPress={onPress}>
                { children }
            </TouchableNativeFeedback>
        )
    }else {
        return (
            <TouchableOpacity onPress={onPress}>
                { children }
            </TouchableOpacity>
        )
    }
}

export default CommonButton;

  1. 从上面的例子可知Platform可以用来判断端的类型,如果你觉得一个文件编写两套代码麻烦,可以改成下面的方式:
- common-button.ios.js
- common-button.android.js

在引入文件的时候还是直接写:

import CommonButton from 'xxx/xxx/common-button'
  1. React Native中的flex跟平常的还是有些区别的;

  2. 由于样式的局限性,所以在项目中我想借助float来写瀑布流样式是不支持的,后来实现的方法是采用了拆分成了两列:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fQuwCW3t-1690621985158)(https://secure2.wostatic.cn/static/9SKFkgGqbqcWtHmMG27MnZ/image.png?auth_key=1690620869-5JGFqRM7Ev1dD1bFSa1e8W-0-54ef38f68cb2afb27421cf15a936125c)]

  3. 生成随机数有很多种npm包供使用,比如nanoid,但是它不兼容React Native,这里采用了uuid:

npm i uuid react-native-get-random-values
// store/modules/habit

import { createSlice } from '@reduxjs/toolkit';
import 'react-native-get-random-values';
import { v4 as uuidv4 } from 'uuid';

const defaultList = [
    {
        id: uuidv4(10),
        name: '打卡',
        count: 0,
    },
]

// ...
  1. expo包内置了图标,文档地址:@expo/vector-icons
  2. 路由跳转,在页面props中可以获取navigation对象:
function HabitHome(props) {
  const { navigation } = props;
  
  // ...
  
  // 新增打卡
  const goSetPage = () => {
    navigation.navigate('HabitSet')
  }
  
  // ...
}
  1. 当用户在输入某些内容,会弹出键盘,键盘有时候会挡住页面,可以借助KeyboardAvoidingView组件,本组件可以自动根据键盘的高度,调整自身的 height 或底部的 padding,以避免被遮挡;
  2. 另外键盘弹出之后,我们希望可以在点击其他地方的时候自动收回键盘,那么可以借助TouchableWithoutFeedback,最终代码如下:
function HabitSet(props) {
  // ...

  // 收起键盘
  const onPress = () => {
    Keyboard.dismiss();
  }
  
  return (
    <TouchableWithoutFeedback onPress={onPress}>
      <KeyboardAvoidingView style={styles.container} behavior={Platform.OS == "ios" ? "padding" : "height"}>
        // ...
      </KeyboardAvoidingView>
    </TouchableWithoutFeedback>
  );
}

参考

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在前两篇中,我们介绍了 React Router 和路由的基础知识,以及如何在应用中使用路由。在本篇中,我们将深入学习 React Router,并介绍一些更高级的用法。 ## 动态路由 在前面的教程中,我们已经学习了如何定义静态路由。但是在实际开发中,我们通常需要处理动态路由。例如,我们可能需要在 URL 中传递参数,以便根据参数来渲染不同的组件。 在 React Router 中,我们可以使用 `:param` 来定义动态路由参数。例如,我们可以定义一个动态路由 `/user/:id`,其中 `:id` 表示一个动态参数,表示用户的 ID。当浏览器访问 `/user/123` 时,React Router 会自动将 `123` 作为参数传递给对应的组件。 下面是一个简单的例子: ```jsx import { BrowserRouter as Router, Route, Link } from "react-router-dom"; function User({ match }) { return <h1>Hello, {match.params.id}!</h1>; } function App() { return ( <Router> <div> <ul> <li> <Link to="/user/123">User 123</Link> </li> <li> <Link to="/user/456">User 456</Link> </li> </ul> <Route path="/user/:id" component={User} /> </div> </Router> ); } ``` 在上面的例子中,我们定义了一个动态路由 `/user/:id`,其中 `:id` 表示用户的 ID。当浏览器访问 `/user/123` 时,React Router 会自动将 `123` 作为参数传递给 `User` 组件,并显示 `Hello, 123!`。 同样,当浏览器访问 `/user/456` 时,React Router 会自动将 `456` 作为参数传递给 `User` 组件,并显示 `Hello, 456!`。 ## 嵌套路由 在实际开发中,我们经常需要在一个页面中嵌套多个组件。在 React Router 中,我们可以使用嵌套路由来实现这个功能。 具体来说,我们可以在一个组件中定义多个 `<Route>` 组件,从而实现嵌套路由。例如,我们可以定义一个嵌套路由 `/user/:id/posts`,其中 `:id` 表示用户的 ID,`posts` 表示用户的帖子列表。 下面是一个简单的例子: ```jsx import { BrowserRouter as Router, Route, Link } from "react-router-dom"; function User({ match }) { return ( <div> <h1>Hello, {match.params.id}!</h1> <ul> <li> <Link to={`${match.url}/posts`}>Posts</Link> </li> </ul> <Route path={`${match.path}/posts`} component={Posts} /> </div> ); } function Posts() { return <h2>Posts</h2>; } function App() { return ( <Router> <div> <ul> <li> <Link to="/user/123">User 123</Link> </li> <li> <Link to="/user/456">User 456</Link> </li> </ul> <Route path="/user/:id" component={User} /> </div> </Router> ); } ``` 在上面的例子中,我们定义了一个嵌套路由 `/user/:id/posts`,其中 `:id` 表示用户的 ID,`posts` 表示用户的帖子列表。当浏览器访问 `/user/123/posts` 时,React Router 会自动将 `123` 作为参数传递给 `User` 组件,并显示 `Posts` 组件。 ## 路由守卫 在实际开发中,我们通常需要实现一些路由守卫功能,例如登录验证、权限控制等。在 React Router 中,我们可以使用 `Route` 组件的 `render` 属性来实现路由守卫。 具体来说,我们可以定义一个高阶组件 `AuthRoute`,用来检查用户是否登录。如果用户已登录,则渲染对应的组件;否则,跳转到登录页面。 下面是一个简单的例子: ```jsx import { BrowserRouter as Router, Route, Link, Redirect } from "react-router-dom"; function AuthRoute({ component: Component, ...rest }) { const isAuthenticated = localStorage.getItem("isAuthenticated"); return ( <Route {...rest} render={(props) => isAuthenticated ? ( <Component {...props} /> ) : ( <Redirect to={{ pathname: "/login", state: { from: props.location } }} /> ) } /> ); } function Home() { return <h1>Welcome Home!</h1>; } function Login() { const login = () => { localStorage.setItem("isAuthenticated", true); }; return ( <div> <h2>Login</h2> <button onClick={login}>Login</button> </div> ); } function App() { return ( <Router> <div> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/login">Login</Link> </li> </ul> <AuthRoute exact path="/" component={Home} /> <Route path="/login" component={Login} /> </div> </Router> ); } ``` 在上面的例子中,我们定义了一个高阶组件 `AuthRoute`,用来检查用户是否登录。如果用户已登录,则渲染对应的组件;否则,跳转到登录页面。具体来说,我们首先从本地存储中检查用户是否已登录,然后根据检查结果来渲染对应的组件或跳转到登录页面。 ## 总结 在本篇教程中,我们深入学习React Router,并介绍了一些更高级的用法。具体来说,我们学习了如何定义动态路由、嵌套路由路由守卫。 希望通过本篇教程,你已经掌握了 React Router 的高级用法,并能够在实际开发中灵活使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值