React Native 开发系列5 完成学习模块,社区,账号设置

react-native | Comments

react native开发模式熟悉了之后,很少在碰到新的问题需要解决。上一段时间是一直在用新东西,碰到新的问题,这一段时间就是用之前学到的东西搭积木,完成了学习模块的3种模式、社区和用户设置页面。阅读模块暂时去掉了,app的大部分功能都开发完成,昨天买了Apple的开发者证书,等确认后就能打包测试了。

目录

  1. 项目搭建 – 底部导航栏及搜索
  2. 实现搜索 – 调用API及自定义组件
  3. 登录注册 – 使用cookies
  4. 学习卡片 – flash/swipe card
  5. 学习模块,社区,账号设置

使用axios

之前自己写了一个fetcher把fetch包装了一下,在后面需要发送post和put的请求的时候,server端需要验证Referer和和csrf token,发现axios更好用,就把fetcher用axios重新实现了一遍,主要代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
const instance = axios.create({
  baseURL: "https://souka.io",
  timeout: 5000,
  headers: {
    REFERER: "https://souka.io",
    Accept: "application/json",
    "Content-Type": "application/json"
  },
  transformResponse: [(data) => {
    console.log("fetch data --> ", JSON.parse(data));
    return JSON.parse(data);
  }],
});

除了指定之前的Accept和Content-type之外还加了Referer,而且可以添加一个baseURL,这样在发送请求的时候只需要写路径,不需要完整的域名。

还有一个updateCSRF函数,在每次重新登录时要更新一下本地的csrf token。

1
2
3
4
5
6
const updateCSRF = () => {
  CookieManager.getAll((err, res) => {
    console.log("get all cookies: ", res, err);
    instance.defaults.headers.common["X-CSRFToken"] = res.csrftoken.value;
  });
};

项目结构调整,解决import相对路径问题

之前所有的页面都放在app/screens下面,但是大部分时候一个tab里面会有很多页面,每个tab都是一个StackNavigator, 为了代码结构更清晰,调整了一下screens下面的文件组织,把每个tab的页面放在一个文件夹里面。

随之而来的一个问题是,有的import的时候需要从import xx from ../components/改写成import xx from ../../components,这样下去每次调整路径,import的地方都得改,而且也不好看,不过bable里面已经有babel-plugin-module-resolver插件解决这个问题。

按照他的文档安装配置就可以了,文档上也给了Eslint相关的插件也需要一并安装。

App从后台唤醒后更新数据

https://facebook.github.io/react-native/docs/appstate.html

论坛下拉刷新和加载分页数据

FlatList上自带了refreshControlonEndReached可以用来实现下拉刷新,和请求分页的数据。

修改useragent

iOS中App默认的的user agent只有系统信息,没有app的名字和版本,我有些页面是直接webview兼容的,所以需要判断是否是app中过来的请求,如果判断出是app就用换一个给app用的模版。修改user agent好像没有好用的react native插件,可以直接修改项目里的ios/AppDelegate.m实现。

1
2
3
4
5
6
7
  NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"];
  UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectZero];
  NSString *oldAgent = [webView stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"];
  NSString *newAgent = [oldAgent stringByAppendingString:@" io.souka - "];
  newAgent = [newAgent stringByAppendingString:version];
  NSDictionary *dictionnary = [[NSDictionary alloc] initWithObjectsAndKeys:newAgent, @"UserAgent", nil];
  [[NSUserDefaults standardUserDefaults] registerDefaults:dictionnary];

切换tab时,重置当前页面状态

app中首页是单词任务相关的信息,其中要学习的课程和每天的任务量可以在设置里面修改。修改之后回到单词页面,就需要重新刷新任务信息,react-navigation目前还没有每个单独screen的状态变化的callback,只有最上层的navigator能够拿到页面切换的通知,文档这里有说明,所以需要写一个自定义的component,在里面实现onNavigationStateChange,来判断和重置页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
onNavigationStateChange(prevState, currentState) {
    const stack = currentState.routes[currentState.index];
    if (prevState.index !== 0 && currentState.index === 0 && stack.index === 0) {
      const resetAction = NavigationActions.reset({
        index: 0,
        actions: [
          NavigationActions.navigate({ routeName: stack.routeName })
        ]
      });
      this.navigator._navigation.dispatch(resetAction);
    }
  }
}

打包测试

到目前为止,测试大部分都是在模拟器里面,默认可以用Xcode加载到真机上测试,但是还是从电脑的上获取javascript来执行,离开电脑就跑不起来了。React Native的running-on-device说的不是很清楚,最后是在stackoverflow上找到的一个方法。

1
2
3
4
5
6
1. 生成一个productjs bundle文件
react-native bundle --dev false --entry-file index.ios.js --bundle-output ios/main.jsbundle --platform ios

2. 修改ios/AppDelegate.m中的jsCodeLocation,使用上面生产的文件。(原来那行注释掉,以后开发还要改回来)
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];

这样在用Xcode build到手机里就可以随时使用了。

效果图:

现在的代码 day5

Comments