Button組件
路徑:f8app/js/common/Button.js
Button組件很簡單浓利,但是也用到了很多子組件树绩,一個(gè)一個(gè)來看看
/*f8app/js/common/Button.js*/
'use strict';
var F8Colors = require('F8Colors');//引入顏色常量
var Image = require('Image');//image組件
var LinearGradient = require('react-native-linear-gradient');//漸變色組件二鳄,github登錄按鈕的樣式
var React = require('React');
var StyleSheet = require('StyleSheet');
var { Text } = require('F8Text'); //f8app包裝的組件,打包了一些和文本有關(guān)的子組件
var TouchableOpacity = require('TouchableOpacity');//相當(dāng)于bootstrap的button組件。
var View = require('View');
class F8Button extends React.Component {
props: { //屬性的類型檢測
type: 'primary' | 'secondary' | 'bordered';
icon: number;
caption: string;
style: any;
onPress: () => void;
};
render() {
const caption = this.props.caption.toUpperCase();
let icon;
//如果傳入圖片的屬性影所,則使用這個(gè)屬性,icon是圖標(biāo)僚碎,caption是按鈕的文字
if (this.props.icon) {
icon = <Image source={this.props.icon} style={styles.icon} />;
}
let content;
if (this.props.type === 'primary' || this.props.type === undefined) {
content = (
<LinearGradient
start={[0.5, 1]} end={[1, 1]}
colors={['#6A6AD5', '#6F86D9']}
style={[styles.button, styles.primaryButton]}>
{icon}
<Text style={[styles.caption, styles.primaryCaption]}>
{caption}
</Text>
</LinearGradient>
);
} else {
var border = this.props.type === 'bordered' && styles.border;
content = (
<View style={[styles.button, border]}>
{icon}
<Text style={[styles.caption, styles.secondaryCaption]}>
{caption}
</Text>
</View>
);
}
return (
<TouchableOpacity
accessibilityTraits="button"
onPress={this.props.onPress}
activeOpacity={0.8}
style={[styles.container, this.props.style]}>
{content}
</TouchableOpacity>
);
}
}
const HEIGHT = 50;
var styles = StyleSheet.create({
//...看源碼猴娩,此處省略
});
module.exports = F8Button;
F8Text組件
/*f8app/js/common/F8Text.js*/
'use strict';
import React, {StyleSheet, Dimensions} from 'react-native';
import F8Colors from 'F8Colors';
//封裝text
export function Text({style, ...props}: Object): ReactElement {
return <React.Text style={[styles.font, style]} {...props} />;
}
//封裝標(biāo)題
export function Heading1({style, ...props}: Object): ReactElement {
return <React.Text style={[styles.font, styles.h1, style]} {...props} />;
}
//段落內(nèi)容主體
export function Paragraph({style, ...props}: Object): ReactElement {
return <React.Text style={[styles.font, styles.p, style]} {...props} />;
}
//使用Dimensions組件獲取實(shí)際硬件的寬度
const scale = Dimensions.get('window').width / 375;
//根據(jù)實(shí)際硬件寬度放大得到實(shí)際尺寸的動態(tài)縮放
function normalize(size: number): number {
return Math.round(scale * size);
}
const styles = StyleSheet.create({
h1: {
fontSize: normalize(24), //normalize函數(shù)的使用。
lineHeight: normalize(27),
color: F8Colors.darkText,
fontWeight: 'bold',
letterSpacing: -1,
}
//省略部分代碼
});
TouchableOpacity 組件
封裝了ios和android不同的類型
/*f8app/js/common/F8Touchable.js*/
'use strict';
import React, {
TouchableHighlight,
TouchableNativeFeedback,
Platform,
} from 'react-native';
function F8TouchableIOS(props: Object): ReactElement {
return (
<TouchableHighlight
accessibilityTraits="button"
underlayColor="#3C5EAE"
{...props}
/>
);
}
//根據(jù)動態(tài)或的的操作系統(tǒng)加載不同的組件
const F8Touchable = Platform.OS === 'android'
? TouchableNativeFeedback
: F8TouchableIOS;
module.exports = F8Touchable;
以上幾個(gè)組件LoginButton組件中使用.
關(guān)鍵的幾個(gè)地方:根據(jù)狀態(tài)加載組件的文字勺阐,es6的異步競爭操作卷中,redux的connect函數(shù)的使用。
/*f8app/js/common/LoginButton.js*/
'use strict';
const React = require('react-native');
const {StyleSheet} = React;
const F8Button = require('F8Button');
const { logInWithFacebook } = require('../actions'); //loginbutton要dispatch的函數(shù)
const {connect} = require('react-redux'); //connect函數(shù)
class LoginButton extends React.Component {
props: {
style: any;
source?: string; // For Analytics
dispatch: (action: any) => Promise;
onLoggedIn: ?() => void;
};
state: {
isLoading: boolean;
};
_isMounted: boolean;
constructor() {
super();
this.state = { isLoading: false };
}
componentDidMount() {
this._isMounted = true;
}
componentWillUnmount() {
this._isMounted = false;
}
render() {
//根據(jù)isLoading的狀態(tài)決定加載那個(gè)組件
if (this.state.isLoading) {
return (
<F8Button
style={[styles.button, this.props.style]}
caption="Please wait..."
/>
);
}
return (
<F8Button
style={[styles.button, this.props.style]}
icon={require('../login/img/f-logo.png')}
caption="Log in with Facebook"
onPress={() => this.logIn()}
/>
);
}
//登錄的異步操作
async logIn() {
const {dispatch, onLoggedIn} = this.props; //通過connect注入的dispatch和onLOggedIN函數(shù)
this.setState({isLoading: true});//點(diǎn)擊登錄按鈕渊抽,改變isLoading的狀態(tài)
try {
await Promise.race([ //下面兩個(gè)異步函數(shù)式競爭關(guān)系蟆豫,第一個(gè)在1.5秒沒完成就會執(zhí)行超時(shí)函數(shù)tiemout
dispatch(logInWithFacebook(this.props.source)),//dispatch登錄函數(shù)
timeout(15000),//超時(shí)函數(shù)
]);
} catch (e) {
const message = e.message || e;
if (message !== 'Timed out' && message !== 'Canceled by user') {
alert(message);
console.warn(e);
}
return;
} finally {
this._isMounted && this.setState({isLoading: false});
}
onLoggedIn && onLoggedIn();
}
}
async function timeout(ms: number): Promise {
return new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('Timed out')), ms);
});
}
var styles = StyleSheet.create({
button: {
alignSelf: 'center',
width: 270,
},
});
//connect應(yīng)該是redux學(xué)習(xí)的一個(gè)難點(diǎn)和突破點(diǎn),UI組件通過connect
//可以獲取全局的所有的state,redux里面只有一個(gè)state樹懒闷。但是
//LoginButton的狀態(tài)是自己決定的十减,因此沒有注入state
//redux還可接受UI組件的dispatch函數(shù)傳遞的action和相應(yīng)的實(shí)參,
//如果這里的action和redux的actiontype想匹配就就導(dǎo)致相應(yīng)的State的改變愤估。
//這個(gè)組件state應(yīng)該返回登錄的token供其他組件來使用帮辟。
module.exports = connect()(LoginButton);