【水滴石穿】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项目
作者:jser_dimple
-------------------------------------------
个性签名:一个人在年轻的时候浪费自己的才华与天赋是一件非常可惜的事情
如果觉得这篇文章对你有小小的帮助的话,记得在右下角点个“推荐”哦,博主在此感谢!
万水千山总是情,打赏5毛买辣条行不行,所以如果你心情还比较高兴,也是可以扫码打赏博主,哈哈哈(っ•̀ω•́)っ✎⁾⁾!
微信
支付宝