Skip to content

FutureOfRussia/rn-skeleton

Repository files navigation

runs with expo

rn-skeleton

React Native skeleton project.

Usage

  • Install Expo CLI

    npm install -g expo-cli # in the root directory
  • Install Expo client for iOS and Android

  • Clone repository

    git clone https://github.com/FutureOfRussia/rn-skeleton.git
  • Install project dependencies

    Navigate to the project folder in your terminal cd rn-skeleton and run npm install.

  • Starting the development server

    Type expo start to start the local development server of Expo CLI.

  • Opening the app on your phone/tablet

    • 🍎 On your iPhone or iPad, open the default Apple "Camera" app and scan the QR code you see in the terminal or in Expo Dev Tools.
    • 🤖 On your Android device, press "Scan QR Code" on the "Projects" tab of the Expo client app and scan the QR code you see in the terminal or in Expo Dev Tools.

Custom components

Button with bouncing animation. Based on Pressable component from React Native and React Native Reanimated animation.

Usage example

<BounceButton onPress={() => console.log('Hello World!')}>
  <Text>Press</Text>
</BounceButton>

Props

debounce

Determines if the debounce module is enabled. To use this module, an useDebounce hook must be placed in the root component.

Type Required Default
bool No false

disabled

Specifies the disabled state of the button.

Type Required Default
bool No false

haptic

Enabled vibration when pressed and released.

Type Required Default
bool No false

hitSlop

Sets additional distance outside of element in which a press can be detected.

Type Required Default
number No 10 px

onPress

Press event callback.

Type Required
function No

style

Supports animated styles.

Type Required
style No

Button with opacity animation. Based on Pressable component from React Native.

Usage example

<OpacityButton onPress={() => console.log('Hello World!')}>
  <Text>Press</Text>
</OpacityButton>

Props

debounce

Determines if the debounce module is enabled. To use this module, an useDebounce hook must be placed in the root component.

Type Required Default
bool No false

disabled

Specifies the disabled state of the button.

Type Required Default
bool No false

hitSlop

Sets additional distance outside of element in which a press can be detected.

Type Required Default
number No 10 px

onLongPress

Long press event callback.

Type Required
function No

onPress

Press event callback.

Type Required
function No

style

Type Required
style No

Component for displaying local push notifications.

Usage example

In the root component:

import { LocaleNotification } from './components/LocaleNotification'

return (
  <View>
    <App />
    <LocaleNotification />
  </View>
)

Call from anywhere:

import { pushNotification } from '../LocaleNotification'

return (
  <BounceButton onPress={() => pushNotification({ msg: 'Hello World!' })}>
    <Text>Press</Text>
  </BounceButton>
)

API

pushNotification(notification) - Push a new Notification to the event loop.

Arguments:

  • notification (Notification) -- Notification object.

Notification

  • msg (string - require) - Notification text.
  • action (function) - If passed, the action button will be displayed. Callback of the action button.
  • actionLabel (string) - Action button label. Default value - 'Ok'.

Component for managing Expo OTA updates. If there is an available update for the application, a banner will be shown with which you can install this update and restart the application. Uses expo update module.

Usage example

In the root component:

import { UpdateBanner } from './components'

return (
  <View>
    <App />
    <UpdateBanner />
  </View>
)

Used to process requests to the server and its responses.

import AsyncStorage from '@react-native-async-storage/async-storage'
import axios, { AxiosInstance } from 'axios'
import { apiEndpoint } from '../constants'

export default function HttpClient(): AxiosInstance {
  const config = {
    baseURL: `${apiEndpoint}`, // base path to API
    headers: { 'Content-Type': 'application/json' },
  }

  const axiosInstance = axios.create(config)

  axiosInstance.interceptors.request.use(async (_conf) => {
    // get authorization token from device storage
    const token = JSON.parse((await AsyncStorage.getItem('token')) || '')
    const conf = _conf

    // checking the token and adding it to the request header
    if (token && moment.unix(token.expiration_date).isAfter(moment())) {
      conf.headers.Authorization = `Bearer ${token.access_token}`
    }

    return conf
  }, (error) => Promise.reject(error))

  axiosInstance.interceptors.response.use((response) => response, async (error) => {
    console.log(error) // here you can process the server response
    return Promise.reject(error)
  })

  return axiosInstance
}

Usage example

const getUserImages = async (id: number) => {
  const { data } = await HttpClient.get('api/images', { params: { user_id: id } })
  console.log(data)
}

Using Redux with the Rematch library

Types

// types.ts

export type Values = {
  title: string
}

export type State = {
  values: Values
}

export type Dispatch = {
  values: {
    changeTitle: (payload: string) => Values
    changeTitleAsync: (payload: string) => Promise<void>
  }
}

Model

The model brings together state, reducers, async actions & action creators in one place.

// values.ts
import { Values, Dispatch, State } from './types'

const initialState: Values = {
  title: "It's React Native project!", // initial state
}

export default {
  state: initialState,
  reducers: {
    // handle state changes with pure functions
    changeTitle: (state: Values, payload: string): Values => ({ ...state, title: payload }),
  },
  effects: (dispatch: Dispatch) => ({
    // handle state changes with impure functions.
    // use async/await for async actions
    changeTitleAsync: async (payload: string, state: State) => {
      await new Promise((resolve) => setTimeout(resolve, 1000))
      dispatch.main.changeTitle(payload)
    },
  }),
}

Store

Connect all models to the store.

// store.ts

import { init } from '@rematch/core'
import values from './values'

export default init({ models: { values } })

Wrap the root component in a provider.

// App.tsx

import { Provider } from 'react-redux'
import store from './store'

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

Selector and Dispatch

Use hooks from react-redux to get and modify store data.

import { useDispatch,useSelector } from 'react-redux'
import { Dispatch, State, Values } from './types'

function TextInputWithRedux() {
  const { state: { changeTitle } } = useDispatch<Dispatch>()
  const { title } = useSelector<State, Values>((state) => state.values)

  return <TextInput value={title} onChangeText={(value) => changeTitle(value)} />
}

Libraries

About

React Native skeleton project.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors