Upgrade to Pro — share decks privately, control downloads, hide ads and more …

How To React Native

Dmitry
June 07, 2017

How To React Native

Talk about React Native things. Mobile JS Buzz II

Dmitry

June 07, 2017
Tweet

Other Decks in Programming

Transcript

  1. JS Движок JavaScript Core. Babel под капотом и свой react-native

    пресет Поддержка ES6 и ES7 фич Полифиллы для ES6-ES7 методов Object, Array и String; а также для XMLHttpRequest, fetch, консоли, тайм-аутов и тд.
  2. components/text/styles.js import { StyleSheet } from 'react-native' import * as

    Styles from '@styles' export default StyleSheet.create({ default: { fontSize: Styles.fontSizes.normal, fontFamily: Styles.fonts.primaryFont, color: Styles.colors.dark, }, bold: { fontWeight: ‘bold’ }, "/* other styles "*/ })
  3. import { create } from ‘react-native-platform-stylesheet' export default create({ default:

    { fontSize: 18, ios: { fontFamily: 'Helvetica' }, android: { fontFamily: 'Roboto' } } }) components/text/styles.js, платформозависимый код
  4. import { create } from ‘react-native-platform-stylesheet' export default create({ default:

    { fontSize: 18, ios: { fontFamily: 'Helvetica' }, android: { fontFamily: 'Roboto' } } }) components/text/styles.js, платформозависимый код
  5. { "/* ""... "*/ "rnpm": { "assets": [ "fonts" ]

    } } Кладем свои шрифты в fonts/ и обновляем package.json $ react-native link assets
  6. import styles from './styles.js' const Text = ({children, ""...props}) !=>

    { const { bold, color, style: styleExtension, ""...otherProps } = props const style = [ styles.default, styleExtension, bold !&& styles.bold, color !&& { color }, ] return ( <RNText {""...otherProps} style={style}> {children} "</RNText> ) } components/text/index.js, теперь со стилями
  7. import styles from './styles.js' const Text = ({children, ""...props}) !=>

    { const { bold, color, style: styleExtension, ""...otherProps } = props const style = [ styles.default, styleExtension, bold !&& styles.bold, color !&& { color }, ] return ( <RNText {""...otherProps} style={style}> {children} "</RNText> ) } components/text/index.js, теперь со стилями
  8. import Color from 'color' const teal = Color('teal') const gray

    = Color('dimgray') const darker = color !=> color.darken(0.25) const withOpacity = color !=> color.alpha(0.8) export default { dark: gray, darker: darker(gray), primary: teal, primaryWithOpacity: withOpacity(teal), } styles/colors.js, используем npm модуль color
  9. Платформозависимый код const OS = Platform.OS "// 'android' or 'ios'

    const platform = Platform.select({ ios: 'ios', android: 'android' }) ├── filename.js "// кросплатформенный файл ├── filename.ios.js "// iOS └── filename.android.js "// Android
  10. Animated API LayoutAnimation API class SpinningImage extends React.Component { spinValue

    = new Animated.Value(0) componentDidMount() { this.spin() } spin = () => { this.spinValue.setValue(0) Animated.timing(this.spinValue, { toValue: 1, duration: 2000, easing: Easing.linear, useNativeDriver: true, }).start(this.spin) } render() { const spin = this.spinValue.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '360deg'] }) const transform = [{rotate: spin}] const style = [styles.image, {transform}] return ( <View> <Animated.Image style={style} source={myImage}/> </View> ) } } if (Platform.OS === 'android') { UIManager.setLayoutAnimationEnabledExperimental(true); } class BoxWithSizeChanges extends React.Component { state = {size: 200} increaseSize = () => { LayoutAnimation.spring() // OR LayoutAnimation.configureNext(CUSTOM_CONFIG) this.setState(state => ({size: state.size + 50})) } render() { const {size} = this.state const sizes = {height: size, width: size} const style = [styles.box, sizes] return ( <View> <Box style={style}/> <Button onPress={this.increaseSize} title=‘Make him bigger!’/> </View> ) } }
  11. oblador/react-native-animatable <Animatable.Text animation="slideInDown" iterationCount={5} direction="alternate"> Up and down you go

    </Animatable.Text> <Animatable.Text animation="pulse" easing="ease-out" iterationCount="infinite" style={{textAlign: 'center'}}> ❤ </Animatable.Text>
  12. Примеры, компоненты Router & Scene <Router> <Scene key="root"> <Scene key="home"

    component={Home} title="Home" "/> <Scene key="about" component={About} title="About" "/> <Scene key="wrapper" hideNavBar> {"/* Nested scenes "*/} "</Scene> "</Scene> "</Router>
  13. Примеры, использование Actions <Router> <Scene key="root"> <Scene key="home" component={Home} title="Home"

    "/> <Scene key="about" component={About} title="About" "/> <Scene key="wrapper" hideNavBar> {"/* Nested scenes "*/} "</Scene> "</Scene> "</Router> class About extends React.Component { goHome = () "=> Actions['home']() popHome = () "=> Actions.pop() goHomeWithParams = () "=> Actions['home']({ iWillBeAvailableThroughPropsAtHome: ‘Hi there!’ }) "/* render etc "*/ }
  14. Примеры, вспомогательные функции const createScene = (key, {title, ""...props}) "=>

    <Scene key={key} sceneStyle={{padding: 64}} renderLeftButton={() "=> <MenuToggle "/>} title={(title "|| key).toUpperCase()} {""...props} "/> const Scenes = ( <Scene key="drawer" component={Drawer}> <Scene key="wrapper"> {createScene('home', {component: Home, initial: true})} {createScene('about', {component: About})} {createScene('logout', {component: Logout, title: 'Log Out'})} "</Scene> "</Scene> )
  15. Примеры, Drawer import Drawer from 'react-native-drawer' import { DefaultRenderer, Keyboard

    } from 'react-native-router-flux' "/* Drawer render "*/ const {navigationState, onNavigate} = props return ( <Drawer {""...drawerProps} open={navigationState.isOpen} content={<WrappedComponent "/>} onOpenStart={Keyboard.dismissKeyboard}> <DefaultRenderer onNavigate={onNavigate} navigationState={navigationState.children[0]} "/> "</Drawer> )
  16. Примеры, Sub-scenes const ProfileScenes = ( <Scene key="profile" component={Profile} title="My

    Profile"> <Scene key="profile/view" "/> <Scene key="profile/edit" editMode rightTitle="Save" onRight={saveProfile} leftTitle="Cancel" onLeft={backToViewMode} "/> <Scene key="profile/save" save "/> "</Scene> ) Примеры, Switch <Scene key="root" tabs={true} unmountScenes component={connect(state "=> ({session: getSession(state)}))(Switch)} selector={props "=> props.session ? 'main' : 'unauthorized'} > <Scene key="unauthorized" component={Unauthorized} "/> <Scene key="main" component={Main} "/> "</Scene>
  17. Примеры, StackNavigator StackNavigator({ Home: { screen: HomeScreen, navigationOptions: ({navigation}) "=>

    ({ title: 'Home', headerRight: <Button onClick={navigation.navigate('somewhere')} "/>, header: <CustomHeader "/> "/* other screen props "*/ }) }, About, "/* other screens "*/ }, { headerMode: 'float', initialRouteName: 'Home' "/* other StackNavigator props "*/ })
  18. Примеры, TabNavigator TabNavigator({ Home: { screen: HomeScreen, navigationOptions: ({navigation}) "=>

    ({ tabBarLabel: 'Home', tabBarIcon: ({tintColor}) "=> <Icon tint={tintColor}"/> }) }, Feed, "/* other tabs "*/ }, { tabBarComponent: TabBarBottom, tabBarOptions: { activeTintColor: 'teal', "/* other tabBar props "*/ }, "/* other TabNavigator props "*/ })
  19. Примеры, DrawerNavigator DrawerNavigator({ Home: { screen: HomeScreen, navigationOptions: ({navigation}) "=>

    ({ drawerLabel: 'Home', drawerIcon: ({tintColor}) "=> <Icon tint={tintColor}"/> }) }, Profile, "/* other tabs "*/ }, { activeTintColor: 'teal', contentComponent: props "=> <ScrollView><DrawerItems {""...props} "/>"</ScrollView> "/* other DrawerNavigator props "*/ })
  20. Примеры, nested navigators StackNavigator({ Tabs: { screen: TabNavigator({ "/* tabs

    "*/ }) }, Stack: { screen: StackNavigator({ "/* screens "*/ }) } })
  21. Примеры, screen props this.props.navigation = { dispatch, goBack, navigate, "/*

    few more "*/ } NavigationActions NavigationActions.navigate({ routeName: 'Profile', actions: [ NavigationActions.navigate({ routeName: 'Friends', }) ] })
  22. erikras/ducks-modular-redux import { createAction, handleActions } from 'redux-actions' import {

    moduleName } from './config' // moduleName = 'todosModule' const initialState = {todos: []} // MAY export action type, if it should be accessible // in other parts of the app (e.g. redux-saga or other module) const TODO_ADD = `${moduleName}/TODO_ADD` // MUST export creators export const addTodo = createAction(TODO_ADD) // MUST export reducer as default export default handleActions({ [TODO_ADD]: (state, {payload}) => ({todos: […state, payload]}) }, initialState); // selectors, sagas, epics etc. MAY also be named export redux/modules/todos/index.js
  23. import { createSelector } from 'reselect' import { moduleName }

    from ‘./config' export const getTodos = state => state[moduleName].todos export const getVisibilityFilter = state => state[moduleName].filter export const getVisibleTodos = createSelector( [getTodos, getVisibilityFilter], (todos, visibilityFilter) => { switch (filter) { case 'SHOW_ALL': return todos case 'SHOW_COMPLETED': return todos.filter(todo => todo.completed) case 'SHOW_ACTIVE': return todos.filter(todo => !todo.completed) } } ) // todoList.js | import * as todosSelectors from '@modules/todos/selectors' redux/modules/todos/selectors.js reactjs/reselect
  24. Redux-Thunk const a = <div onClick={ () => dispatch(actions.loadUser(userId)) }>{username}</div>

    export const loadUser = userId => async dispatch => { try { const user = await userService.load(userId) dispatch(userLoaded(user)) } catch (err) { dispatch(userLoadFailed(err)) } } const a = <div onClick={ () => dispatch(actions.userNameClicked(userId)) }>{username}</div> function * watchUserNameClickAndLoad () { yield * takeLatest(USER_NAME_CLICKED, loadUser) } function * loadUser ({payload}) { try { const user = yield call(userService.load, payload) yield put(userLoaded(user)) } catch (err) { yield put(userLoadFailed(err)) } }
  25. Хелперы / Эффекты • take (watcher) • takeLatest (cancels previous)

    • takeEvery • call (blocking) • fork (non-blocking) • put (saga dispatch) • select (saga mapState) • delay • cancel • race && all (like in Promises) etc.
  26. redux-saga: login flow example function * authorization () { //

    Check the storage for cached token and profile let [token, profile] = yield [ call(auth.getToken), call(auth.getProfile), ] // so now user may be logged in... }
  27. redux-saga: login flow example // ...or may not, so we

    gonna wait for it if (!token) { const {payload: credentials} = yield take(profileActions.SIGN_IN) const {response, error} = yield call(authRequest, credentials) if (error) { yield put(profileActions.signInFailed(error)) continue } token = response.token profile = response.profile yield [ call(auth.setToken, token), call(auth.setProfile, profile), ] }
  28. redux-saga: login flow example // Now when we have token

    and profile // We can let user in yield put(profileActions.signInSuccess({token, profile})) yield take(profileActions.SIGN_OUT) token = profile = null yield [ call(auth.removeToken), call(auth.removeProfile), ] yield put(stackActions.clear()) yield put(profileActions.signOutSuccess())
  29. redux-saga: login flow example function * authorization () { //

    Check the storage for cached token and profile let [token, profile] = yield [call(auth.getToken), call(auth.getProfile)] while (true) { if (!token) {…} /* Receive token and profile data */ yield put(profileActions.signInSuccess({token, profile})) yield take(profileActions.SIGN_OUT) /* Other signOut stuff */ } }
  30. По максимуму используйте PropTypes и DefaultProps Для клавиатуры используйте KeyboardAvoidingView

    Внимательно изучайте документацию Не пренебрегайте селекторами Найдите в себе силы разобраться с Redux-Saga - не пожалеете Не забывайте убивать console.log, когда льете в прод И конечно же пишите на React Native - он крутой inline-советы напоследок