Skip to content

11 迁移手册

吴磊 edited this page Jan 11, 2019 · 1 revision

迁移手册

  1. 调整目录结构,根目录增加index.jsindex.ios.js

    // index.js
    import App from "./Main";
    import { Package } from "miot";
    Package.entry(App);
    
    // index.ios.js
    import "./index.js";
  2. 原有的Main/index.ios.js更名为Main/index.js,删掉其中注册app入口的一行:AppRegistry.registerComponent()

  3. 安装插件使用的第三方库(框架package.json中未包含)。比如闹钟使用到的react-native-swipeout

  4. 引用依赖尽量使用es6的import,而不是require

  5. RN54废弃了react-native中的Component,所有组件将继承reactComponent

    // old
    var React = require('react-native');
    var {
      StyleSheet,
      Text,
      DeviceEventEmitter,
      PixelRatio,
    } = React;
    
    // new
    import React from 'react';
    import {
      StyleSheet,
      Text,
      DeviceEventEmitter,
      PixelRatio,
    } from 'react-native';
  6. RN54将PropTypesreact-native中抽离出来,独立成prop-types

    // old
    var propTypes = {
      source: React.PropTypes.object,
      highlightedSource: React.PropTypes.object,
      onPress: React.PropTypes.func,
    };
    
    // new
    import PropTypes from 'prop-types';
    // ...
    var propTypes = {
      source: PropTypes.object,
      highlightedSource: PropTypes.object,
      onPress: PropTypes.func,
    };
  7. React.createClass报错解决方案

    // old
    var ImageButton = React.createClass({
      propTypes: propTypes,
      getInitialState: function() {
      },
      getDefaultProps: function() {
      },
      //...
      render: function() {
      },
    })
    
    // new
    // RN54不再支持使用createClass创建组件, 改为继承至React.Component
    // key-value形式改为声明语句
    export default class ImageButton extends React.Component {
      static propTypes = propTypes;
      static initialState = {
      };
      static defaultProps = {
      };
      //...
      render() {
      }
    }
  8. 切换路由框架(❗️)

    • 所有页面删除之前的路由相关代码:

      // old
      class MyComponent extends React.Component {
      	// ...
      }
      
      // ...
      
      var route = {
        title: xxx,
        component: MyComponent,
        navBarStyle: {
          backgroundColor: '#f2f2f2',
        },
      };
      
      module.exports = {
        component: MyComponent,
        route: route,
      }
      
      // new
      export default class MyComponent extends React.Component {
      	// ...
      }
      
      // ...
      
      // 摈弃之前的路由系统写法
      // var route = {
      //  title: xxx,
      //  component: MyComponent,
      //  navBarStyle: {
      //    backgroundColor: '#f2f2f2',
      //  },
      //};
      
      // module.exports = {
      //  component: MyComponent,
      //  route: route,
      // }
    • 在入口文件Main/index.js中集中管理所有的页面,增加以下代码:

      // 导航相关组件
      import { createStackNavigator } from 'react-navigation';
      import { TitleBarBlack } from 'miot/ui';
      // 导入所有的页面
      import SceneMain from './SceneMain';
      import MainPage from './MainPage';
      import MHSetting from './MHSetting';
      // ...
      
      const RootStack = createStackNavigator(
        {
          // ...
          SceneMain: SceneMain,
          MainPage: MainPage,
          MHSetting: MHSetting,
          // ...
        },
        {
          initialRouteName: 'MainPage',
          navigationOptions: ({ navigation }) => {
            return {
              header: <TitleBarBlack title={navigation.state.params ? navigation.state.params.title : ''} style={{ backgroundColor: '#fff' }}
                onPressLeft={() => {
                  navigation.goBack();
                }} />,
            };
          },
        }
      );
    • 页面跳转,包括参数传递和参数获取

      // old
      this.props.navigator.push({
        // 跳转页面
        route,
        // 传参,在跳转页面中可通过props直接访问,即:this.props.key
        passProps: {
          key: value
        },
      });
      
      // new
      this.props.navigation.navigate('ComponentName', {
        key: value
      });
      // 在跳转页面获取参数
      // method 1
      this.props.navigation.state.params.key
      // method 2
      this.props.navigation.getParam("key");
    • 返回上级页面

    • // old
      this.props.navigator.pop();
      
      // new
      this.props.navigation.goBack();
    • 退出插件

    • // old
      MHPluginSDK.closeCurrentPage();
      
      // new
      import { Package } from "miot";
      Package.exit()
    • 页面自定义导航栏

      // 所有页面默认沿用index.js中RootStack定义的导航栏样式
      const RootStack = createStackNavigator(
      ...
          navigationOptions: ({ navigation }) => {
            return {
              header:
                <TitleBarBlack
                  title={navigation.state.params ? navigation.state.params.title : ''}
                  style={{ backgroundColor: '#fff' }}
                  onPressLeft={() => { navigation.goBack() }}
                />,
            };
          },
      ...
      );
      
      // 自定义导航栏样式
      export default class AddReminder extends React.Component {
        // 表示不使用默认的导航栏
        static navigationOptions = ({ navigation }) => {
          return {
            header: null
          };
        };
        
        //...
      
        render() {
          return (
              // 自定义标题的样式和颜色,左右按钮的样式、颜色以及绑定事件
              <TitleBarBlack
                title="newTitle" style={{ backgroundColor: 'red' }}
                onPressLeft={() => { this.props.navigation.goBack() }}
                rightText="save"
                leftText="cancel"
                onPressRight={() => {
                  this._save();
                }}
              />
            //...
          )
        }
    • 监听导航栏的生命周期

      // old
      // 可监听'willfocus'和'didfocus'
      this._didFocusListener = DeviceEventEmitter.addListener('didfocus', ({route}) => {
        console.log(route);
      }
      
      // new
      // 可监听'willBlur', 'willFocus', 'didFocus', 'didBlur'
      this._didFocusListener = this.props.navigation.addListener('didFocus', payload => {
        console.log(payload);
      }
    • 导航栏更新机制

        // Eg. change device name
        static navigationOptions = ({ navigation }) => {
          return {
            header:
              <TitleBarBlack
                title={navigation.state["params"] ? navigation.state.params.name : Device.name}
                style={{ backgroundColor: '#fff' }}
                onPressLeft={() => { Package.exit() }}
                onPressRight={() => {
                  navigation.navigate('MHSetting', { 'title': '设置' });
                }}
              />
          };
        };
      
        // 设置中改名之后,首页title同步改名
        this._deviceNameChangedListener = DeviceEvent.deviceNameChanged.addListener((device) => {
          this.props.navigation.setParams({
            name: device.name
          });
          this.forceUpdate();
        });
  9. 组件相关

  • 新框架调整了ImageButton,适用于两个平台。

    // old
    var ImageButton = require('../CommonModules/ImageButton');
    
    // new
    import ImageButton from 'miot/ui/ImageButton';
  • Image不再允许嵌套

    // old
    <Image>
      <Text></Text>
    </Image>
    // old,✅
    <Animated.Image>
      <Animated.Text></Animated.Text>
    </Animated.Image>
    
    // new
    <ImageBackground>
      <Text></Text>
    </ImageBackground>
    // not allowed,❌
    <Animated.ImageBackground>
      <Animated.Text></Animated.Text>
    </Animated.ImageBackground>
    // alternative solution,👌
    <Animated.Image/>
    <Animated.View style={{position:'absolute'}}>
      <Animated.Text></Animated.Text>
    </Animated.View>
  • SwitchIOS废弃,Switch跨平台解决方案

    // old
    <SwitchIOS>
    </SwitchIOS>
    
    // new
    // cross-platform solution
    import { RkSwitch } from 'react-native-ui-kitten';
    <RkSwitch>
    </RkSwitch>
  • DatePicker跨平台解决方案

    // old
    import {DatePickerIOS} from 'react-native'
    
    <DatePickerIOS
      style={styles.datePicker}
      date={this.state.time}
      mode="time"
      onDateChange={(d) => this.setState({ time: d })}
    />
    
    // new 
    // cross-platform,推荐使用第三方库rmc-date-picker
    // 常用属性和之前几乎一致,UI也能满足要求
    import DatePicker from "rmc-date-picker";goBack
    <DatePicker
      style={styles.datePicker}
      defaultDate={this.state.time}
      mode="time"
      onDateChange={(d) => this.setState({ time: d })}
      use12Hours={true}
      locale={LocalizedStrings}
    />
  • Picker跨平台解决方案

    // old
    import {Picker} from 'react-native'
    
    <Picker
      selectedValue={this.state.pickerValue}
      style={styles.picker}
      onValueChange={(v) => this._setPickerValue(v)}>
      <Picker.Item label={"1"} value={1} />
      <Picker.Item label={"2"} value={2} />
      <Picker.Item label={"3"} value={3} />
    </Picker>
        
    // new
    // cross-platform,推荐使用第三方库rmc-picker
    // Picker属性一致,Picker.Item换成Text即可
    import Picker from "rmc-picker";
    
    <Picker
      selectedValue={this.state.pickerValue}
      style={styles.picker}
      onValueChange={(v) => this._setPickerValue(v)}>
      <Text label={"1"} value={1}>1</Text>
      <Text label={"2"} value={2}>2</Text>
      <Text label={"3"} value={3}>3</Text>
    </Picker>
  • 提示的跨平台解决方案

    // old
    MHPluginSDK.showLoadingTips("loading");
    MHPluginSDK.dismissTips();
    MHPluginSDK.showFailTips("fail");
    MHPluginSDK.showFinishTips("finish");
    AlertIOS.alert();
    
    // new
    import {
      LoadingDialog,
      MessageDialog
    } from "miot/ui/MessageDialog";
    
    <LoadingDialog
      title='title'
      message='message'
      onDismiss={() => {}}
      visible={this.state.visible}
    />
    
    <MessageDialog
      title='title'
      message='message'
      cancel='cancel'
      confirm='ok'
      onCancel={() => {}}
      onConfirm={() => {}}
      onDismiss={() => {}}
      visible={this.state.visible}
    />
  1. 图片以及其他资源的引用方式
// old
<Image
source={{ uri: MHPluginSDK.basePath + imagePath + imageName }}
style={{ width: x, height: y }}
/>
<Image 
style={styles.icon} 
source={this.props.app.sourceOfImage(imageName)}
/>

// new
// 不再提供basePth
// static image
<Image
source={require(relativeImagePath + imageName)}
style={{ width: x, height: y }}
/>
// dynamic image at local cache for plugin
<Image
source={{local: imageName}} //local file name
style={{ width: x, height: y }}
/>
<Image
source={{uri: urlToGetImage}} //remote url for image
style={{ width: x, height: y }}
/>
  1. 其他

    • TouchableWithoutFeedback包含的视图在Android中无法响应滚动手势
    • Text设置属性numberOfLines显示多行文字,在Andorid平台可能会出无法完全显示的问题,可以考虑加上字体或者切换字体。
    • 旧框架的页面以屏幕左上角为起点定位,所以需要设置marginTop为64,新框架以导航栏底部为起点定位,不再需要marginTop
Clone this wiki locally