【水滴石穿】ReactNative-Redux-Thunk

老实说,运行出来的项目让人失望,毕竟我想看各种有趣的demo啊~
先放上源码地址:https://github.com/ludejun/ReactNative-Redux-Thunk
我们来一起看看代码有没有什么有趣的地方,要是没有,只能gg
看到引用了这几个插件,看看代码是怎么使用的

 "react-redux": "^6.0.0",
    "redux": "^4.0.1",
    "redux-logger": "^3.0.6",
    "redux-thunk": "^2.3.0",

这个状态处理一个是数据的加减,一个就是登陆退出登陆的状态

//index.js
//定义了引用的根组件是root
/**
 * @format
 * @lint-ignore-every XPLATJSCOPYRIGHT1
 */

import {AppRegistry} from 'react-native';
import Root from './src/Root';
import {name as appName} from './app.json';

AppRegistry.registerComponent(appName, () => Root);

我们来看看root.js中是如何处理的
分析代码可知root.js中主要是进行热更新的,在热更新未完成之前是不会让重启的,热更新完毕之后可以重启

//src/Root.js
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import { createLogger } from 'redux-logger';
import { composeWithDevTools } from 'remote-redux-devtools';
import CodePush from 'react-native-code-push'; // 引入code-push
// 先引用外部组件,然后再引用内部自己定义的组件,这个是引用组件的一种方法
//上面是引用了状态处理的中间件
import reducers from './reducers';
import App from './App';
//中间件store
const loggerMiddleware = createLogger();
const middleware = [thunkMiddleware, loggerMiddleware];
const store = createStore(
  reducers,
  /* preloadedState, */
  composeWithDevTools(
    applyMiddleware(...middleware)
    // other store enhancers if any);
  )
);

if (module.hot) {
  // Enable hot module replacement for reducers
  module.hot.accept(() => {
    const nextRootReducer = require('./reducers/index').default;
    store.replaceReducer(nextRootReducer);
  });
}

// code-push用法: https://github.com/Microsoft/react-native-code-push
const codePushOptions = {
  // 设置检查更新的频率
  // ON_APP_RESUME APP恢复到前台的时候
  // ON_APP_START APP开启的时候
  // MANUAL 手动检查
  checkFrequency: CodePush.CheckFrequency.ON_APP_RESUME,
};

class Root extends Component {
//做的热更新的部分
  componentWillMount() {
    CodePush.disallowRestart(); // 页禁止重启
    this.syncImmediate(); // 开始检查更新
  }

  componentDidMount() {
    CodePush.allowRestart(); // 在加载完了,允许重启
    console.log('🎉🎉🎉🔥');
  }

  // 如果有更新的提示
  syncImmediate = () => {
    CodePush.sync({
      // 安装模式
      // ON_NEXT_RESUME 下次恢复到前台时
      // ON_NEXT_RESTART 下一次重启时
      // IMMEDIATE 马上更新
      installMode: CodePush.InstallMode.IMMEDIATE,
      // 对话框
      updateDialog: {
        // 是否显示更新描述
        appendReleaseDescription: true,
        // 更新描述的前缀。 默认为"Description"
        descriptionPrefix: '更新内容:',
        // 强制更新按钮文字,默认为continue
        mandatoryContinueButtonLabel: '立即更新',
        // 强制更新时的信息. 默认为"An update is available that must be installed."
        mandatoryUpdateMessage: '必须更新后才能使用',
        // 非强制更新时,按钮文字,默认为"ignore"
        optionalIgnoreButtonLabel: '稍后',
        // 非强制更新时,确认按钮文字. 默认为"Install"
        optionalInstallButtonLabel: '后台更新',
        // 非强制更新时,检查到更新的消息文本
        optionalUpdateMessage: '有新版本了,是否更新?',
        // Alert窗口的标题
        title: '更新提示',
      },
    });
  }

  render() {
    return (
      <Provider store={store}>
        <App />
      </Provider>
    );
  }
}

export default CodePush(codePushOptions)(Root);

root中引用了app.js这个是展示页面
这个里面主要是定义tab切换页,写的非常简洁

//src/App.js
// import { createStackNavigator, createAppContainer } from 'react-navigation';
import { createBottomTabNavigator, createAppContainer } from 'react-navigation';
import React from 'react';
import Ionicons from 'react-native-vector-icons/Ionicons';
import { Home, Profile } from './pages';

// 普通路由导航
// const MainNavigator = createStackNavigator({
//   Home: { screen: Home },
//   Profile: { screen: Profile },
// });

// const App = createAppContainer(MainNavigator);

// 分Tab导航o
const TabNavigator = createBottomTabNavigator(
  {
    Home,
    Profile,
  },
  {
    defaultNavigationOptions: ({ navigation }) => ({
      // eslint-disable-next-line
      tabBarIcon: ({ focused, horizontal, tintColor }) => {
        const { routeName } = navigation.state;
        const IconComponent = Ionicons;
        let iconName;
        if (routeName === 'Home') {
          iconName = `ios-information-circle${focused ? '' : '-outline'}`;
          // Sometimes we want to add badges to some icons.
          // You can check the implementation below.
          // IconComponent = HomeIconWithBadge;
        } else if (routeName === 'Profile') {
          iconName = 'ios-options';
        }

        // You can return any component that you like here!
        return <IconComponent name={iconName} size={25} color={tintColor} />;
      },
    }),
    tabBarOptions: {
      activeTintColor: 'tomato',
      inactiveTintColor: 'gray',
    },
  }
);

const App = createAppContainer(TabNavigator);

export default App;

//home页面
//src/pages/Home.js
import React, { Component } from 'react';
import { Platform, StyleSheet, Text, View, Button } from 'react-native';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as homeActions from '../actions/home';

const instructions = Platform.select({
  ios: 'Press Cmd+R to reload,\nCmd+D or shake for dev menu',
  android: 'Double tap R on your keyboard to reload,\nShake or press menu button for dev menu',
});

type Props = {};
class Home extends Component<Props> {
  static navigationOptions = {
    title: '首页',
  };
  // constructor(props) {
  //   super(props);
  // }

  componentDidMount() {
    console.log('🎉🎉🎉🔥');
  }

  onIncrement = () => this.props.homeActions.homeAdd(this.props.count);
  onDecrement = () => this.props.homeActions.homeDecrement(this.props.count);

  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>Welcome to React Native!</Text>
        <Text style={styles.instructions}>To get started, edit App.js</Text>
        <Text style={styles.instructions}>{instructions}</Text>
        <View style={styles.reduxSample}>
          <Button title=" + " style={styles.flexItem} onPress={this.onIncrement} />
          <Text style={styles.flexItem}> {this.props.count} </Text>
          <Button title=" - " style={styles.flexItem} onPress={this.onDecrement} />
        </View>
      </View>
    );
  }
}

const mapStateToProps = ({ home }) => ({
  count: home.count,
});
const mapDispatchToProps = dispatch => ({
  homeActions: bindActionCreators(homeActions, dispatch),
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Home);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
  reduxSample: {
    flex: 0,
    width: 200,
    height: 50,
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
  },
  flexItem: {
    flex: 1,
    textAlign: 'center',
  },
});
//src/pages/Profile.js
import React, { Component } from 'react';
import { StyleSheet, Text, View, Button } from 'react-native';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as userActions from '../actions/user';

class Profile extends Component {
  static navigationOptions = {
    title: '个人信息',
  };
  // constructor(props) {
  //   super(props);
  // }

  componentDidMount() {
    console.log('开始旅程');
  }

  login = () => {
    this.props.userActions.login();
    console.log(1111, this.props.user);
  };

  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>Welcome to Profile!</Text>
        <Button title="Go To Home" onPress={() => this.props.navigation.navigate('Home')} />
        <Button title="登录" onPress={this.login} />
        <Text>
          登录状态:{this.props.user.logged ? '已登录' : '未登录'}
          {this.props.user.fetching && '  fetching...'}
        </Text>
      </View>
    );
  }
}

const mapStateToProps = ({ user }) => ({
  user,
});
const mapDispatchToProps = dispatch => ({
  userActions: bindActionCreators(userActions, dispatch),
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Profile);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5,
  },
});

我们根据login页面来进行分析action,reducer部分,看在profile中是怎么使用的

//src/actions/user.js
//action中定义了对象和dispatch方法
import request from '../utils/fakeRequest';

export const LOGIN_START = 'LOGIN_START';
export const LOGIN_SUCCESS = 'LOGIN_SUCCESS';

export function login(payload) {
  return dispatch => {
    dispatch({ type: LOGIN_START });
    return request(payload, 1500).then(data => {
      dispatch({
        type: LOGIN_SUCCESS,
        payload: data,
      });
    });
  };
}
//reducer中是纯函数
//src/reducers/user.js
import { LOGIN_START, LOGIN_SUCCESS } from '../actions/user';

const initState = {
  logged: false,
  fetching: false,
};

export default function counter(state = initState, action) {
  switch (action.type) {
    case LOGIN_START:
      return {
        ...state,
        fetching: true,
      };

    case LOGIN_SUCCESS:
      return {
        ...state,
        logged: true,
        fetching: false,
      };

    default:
      return state;
  }
}

希望能够看到很有趣很有意思的react-native项目

posted @ 2019-05-23 17:27  jser_dimple  阅读(386)  评论(0编辑  收藏  举报
/*function gotourl() { var url = "https://www.cnblogs.com/smart-girl/"; var localurl = document.url; if( localurl.substring(0,url.length) != url ) { location.href=url; } } gotourl();*/