React Native
Welcome, here is what you will be doing in the next two weeks:
- Brush up on your React Native skills and read through the materials provided by the DECODE
- Develop an app which fetches posts from Tumblr API and present them nicely on the screen. Tumblr documentation: Tumblr
- Start using the React+Redux application architecture
- As you progress, make a new commit every time you finish implementing something (so we can track your progress and give you some useful feedback as you progress) for example:
- When you finish with the 1. make a new commit
- When you finish with adding Navigation component make a new commit
- When you add the ViewModels and LiveData make a new commit
- ... and so on
- Use Git Flow.
Suggested "commit" points are marked as little code blocks like this -> Commit Point.
This way, somebody can take a look and monitor your progress on your feature branch.
Each task is started on its own feature branch.
- After the task is done and when you see a Merge Request annotation, make a merge request from your feature branch to the master branch for somebody to take a final look. Assign it to someone who is assigned to you as your tutor.
- Mark the task step as done on the HRCloud web after the feature/step is approved. Keep in mind that Commit Points roughly if not completely represent tasks on the HR Cloud.
- Please add comments or suggestions to this document using the "add comment" feature visible at the right side of the document. Add a comment or suggestion for everything that is not explained enough or is misleading to you.
- You should have enough time to finish this project in 10 days, so take it slowly to learn as much as you can.
Before you start
- Look up on the Javascript and Node.js courses available on Pluralsight, and get a feel for the Node.js runtime and Javascript as a language
- Get familiar with React.js library for building user interfaces
- Get familiar with React Native framework to develop cross-platform applications:
- Useful intro can be found in this document on Decode’s drive
- Building with React Native is extremely efficient and highly addictive - but getting started can be a little tricky. You should use this guide as a companion to the official Facebook documentation for getting started.
- If you're unfamiliar or have never worked with Git, read up on the basic commands. Also, some of us use SourceTree GUI, which provides a nice user interface for all Git-related actions. Check out Git - Book Sourcetree | Free Git GUI for Mac and Windows Git-FER.
Estimate 1 day
Let’s start
1. Set up your machine
Follow these steps to set up your machine for React Native development:
- We recommend downloading and installing Visual Studio Code text editor for working with Javascript programming language (this is a free text editor, if you prefer paid and more advanced IDEs, something like WebStorm from JetBrains, feel free to use them).
- Download and install the latest version of Apple’s Xcode (skip this if you don’t work on MacOS device) and the latest version of Android Studio from Google and JetBrains.
- Install latest version of Node on your machine - we recommend using Node Version Manager so you can easily change Node versions on your machine.
- Using NPM tool, which is provided within Node installation, install React Native command line interface:
npm install -g react-native-cli
2. Setting up your project
- With React Native CLI you can now create new application using instructions provided by Facebook. Use “React Native CLI Quickstart” and continue from Creating a new application step. Name your app “DecodeOnboarding-yourName”.
- Start source tracking your repo, and make a commit named “Initial commit” and push it to the Bitbucket repo in Onboarding Project
- Commit Point
- Run your app on iOS simulator using react-native-cli command:
react-native run-ios
- Run your app on android emulator/device using react-native-cli command: react-native run-android (for running on android, device should be connected to your machine, or emulator should be already started using android studio)
3. Create initial screen
- Start a new branch on your git repo from your master branch and name it
feature/feed-detail-navigation
and switch to it. - Add new folder
/src
to your project root and inside that folder create/screens
folder - Inside your
/screens
folder create a folder that will contain your first screen, we recommend calling it/feed
because, later in the onboarding process, it should contain a list of elements that represent blog posts. - Create 3 new .js files inside
/feed
folder, you should name them:index.js
,styles.js
andFeedUi.js
- Create new React component inside your empty
index.js
of your new screen folder file using already providedApp.js
in project root as an example. Actually you can just go ahead and and copy all the content of theApp.js
file into the index.js - Now you should go to the file and import your new screen module like this:
import Feed from './src/screens/feed'
and inside a render method of the App.js just return feed as a JSX element <Feed/>
- If everything is done right you should see the same UI layout as before after reloading your device/simulator by pressing
cmd+R
on iOS simulator or2xR
on android emulator. - If you are using a device, just do a shake gesture and you should see Dev action sheet that has a Reload button.
- You should now use 2 remaining files of your new screen to separate
index.js
content into presentation componentFeedUi.js
, and styles filestyles.js
.index.js
will remain as a container component. - Your
FeedUi.js
should be just a function that returns JSX. On the top of the file you must importReact
fromreact
library and also you need to add export statement forFeedUi
function to the bottom of the file so it can be imported from other files. Your file should look something like this:
import React from 'react';
import { Platform, StyleSheet, Text, View } from 'react-native';
import styles from './styles';
const FeedUi = (props) => (
<View style={styles.container}>
<Text style={styles.instructions}>Hello World!</Text>
</View>
)
export default FeedUi;
- Your
styles.js
should be just a styles used in that screen. You can just go ahead and copy the bottom styles constant formindex.js
and paste it into thestyles.js
file. On the top of the file remember to importStyleSheet
fromreact-native
module and also you need to add export statement for styles constant to the bottom of the file so it can be imported from the other files. Your file should look something like this:
import { StyleSheet } from 'react-native';
const styles = StyleSheet.create({...})//existing styles ... here
export default styles;
- Now you should be able to import presentation component (FeedUi) from container component (index.js). Replace JSX returned from the render function of container component with just the presentation element. Your render function of container component should look like this:
render() {
return (
<FeedUi/>
)
}
- Clean and get rid of redundant and unused code from
index.js
. - If everything is done right, you should now see your new message
“Hello World!”
on the screen after reloading. - You now learned how to separate component into presentational and container component.
- This makes the component code much cleaner. It is always recommended to do this with all screens and all new UI components that you create, like buttons, cells, textFields and so on…
- Commit Point
4. Create a list inside a presentational component
- By importing
FlatList
fromreact-native
module, you should now be able to render list inside your presentational component. - Use FlatList documentation as a guide to do this in your own component.
- Create your own cell that you will pass to
renderItem
of theFlatList
. You should do this by creating/cell
folder inside you current screen folder. Just as previous example for the separating presentational and container logic for the Feed screen, create 3 new files: you should name them:index.js
,styles.js
andCellUi.js
- You should have some testing data for
FlatList
. That can be just a simple array of the elements like[{key: 'a'}, {key: 'b'}, {key: 'c'}]
that you can adjust later, and replace with real data from server in the later parts of the onboarding process. - Use
react-native
module to add text elements to your cell. Your cell should display texts and images. Adjust height, shape and alignment of elements as you wish by changing styles of that cell. - Go ahead and play with flexbox. Exact layout is up to you.
- After you are satisfied by the look of your list, commit your work.
- Commit Point
5. Navigate to different screen
- Now you should use the same steps as in 3rd heading section to create an additional screen inside
/screens
folder calledpost
(add/post
folder for that). - Your new screen is meant to present details about blog posts, so it should contain image and text content from blog post.
- Go ahead and create and organize UI as you prefer.
- For navigating to this screen, you have to use a third party library because
react-native
does not provide navigation components by itself. We suggest you use React Navigation. Install it usingnpm
. - Newer versions of
react-navigation
have a sub-dependency. You must also installreact-native-gesture-handler
and maybe some other sub dependencies.npm install --save react-native-gesture-handler
- After installing dependencies that have a native code, you should do a pod install in
ios
folder in order to make it work on iOS:cd ios && pod install && cd ..
- You should add a new folder inside
/src
and call it/navigation
. Inside navigation folder createAppNavigator.js
. InsideAppNavigator.js
file you should create your stack navigator using React Navigation documentation and examples as a guide. Add your existing screens as a routes to your navigator. - Now return your newly created navigator as an only element in
App.js
render method. - You must run your App again in order to see the new changes. Reload is not enough here because you added new modules and did changes to native parts of project.
- You should be able to navigate to different screens. Add some button to your Feed screen or cell inside a list that has an
onPress
callback.
onPress={() => this.props.navigation.navigate('post')}
By pressing this element, you should see app navigating to your post screen.
- If everything is fine, please commit your work now
- Commit Point
Merge request
Estimate 2 days
Real-life content
1. Enable Tumblr API
Follow these steps to show a real-life content in you app:
- Start a new branch on your git repo from your master branch and name it
feature/fetch-real-life-content
and switch to it. - You should use Tumblr’s v2 API, to get an OAuth key you must register an application.
2. Parse content from API
- Choose a Tumblr blog post.
- Use Fetch and replace your test data in your list with data from tumblr blog. Use
componentDidMount
lifecycle method of feed container component. - Create a suitable data structure for a Tumblr blog post response and parse it.
- You must update state of feed container component with the parsed fetch result.
- Pass this data as a prop to presentational component of the feed screen.
- Parse latest 20 posts and present them nicely in the
FlatList
. - Commit Point
3. Add loading spinner
- Show
ActivityIndicator
while you are waiting for the response of fetching posts. Use component state to keep track of loading status. - Commit Point
4. Add paging feature to your list
FlatList
has a callback when you get near the end of a list, while scrolling to the bottom. Use this callback to get the next 20 blog posts from the API and append them to the end of already fetched data.- Your
FlatList
should update with newly added data. - Commit Point
5. Present blog post content in detail screen
- You should pass a blog post id to the detail screen using navigation params argument while navigating.
- Use fetch in
componentDidMount
lifecycle method of post container component to get data for your post id. - Pass this data as a prop to presentational component of the post screen.
- Present data for selected blog post. Update post screen UI (presentational component) to fit all the content.
- Add
ScrollView
to fit all the text returned from API. Parse and show useful content from API as much as you can. - Commit Point
Merge request
Estimate 2 days
Add app state container (Redux)
1. Add Redux modules
- Start a new branch on your git repo from your
master
branch and name itfeature/app-state-container
and switch to it. - Using
npm install
redux and react-redux (Official Redux UI Bindings for React) modules.
2. Create store
- You need to wrap your app inside a
Provider
element fromreact-redux
. - You should create a new top element called
Root.js
in the/src
folder. Also moveApp.js
file to/src
folder. - Store prop must be passed to
Provider
element. UsecreateStore
function provided by theredux
module to create your store. - Commit Point
3. Add Reducers
- Reducer is a function that takes existing state and action as parameters and returns a new state.
- Inside
/src
folder you should create a new folder/reducers
file and inside that file createAppReducer.js
file - Create reducers for the loading and data state, use Redux docs to do so.
- Commit Point
4. Connect your components
- Connect your components to Redux Store by using
connect
function fromreact-redux
module.connect
function takes 2 parameters,mapStateToProps
andmapDispatchToProps
function. - Implement these functions in your component to have a state values available to your component.
- Dispatch an action from component to set a new state of the app.
- Commit Point
5. Add your custom Redux middleware
- Create your own custom middleware
- Use this middleware just to log actions in console
- Commit Point
6. Add Redux-Saga middleware
- Read through the docs of redux-saga
- Using
npm install redux-saga
middleware - You should have both middlewares working side-by-side
- Commit Point
Merge request
Estimate 2 days
Code refactor and new features
1. Move networking logic
- Start a new branch on your git repo from your
master
branch and name itfeature/code-refactor-and-expand
and switch to it. - Create a
fetch.service.js
file, move all the fetch logic to that service. Components should now just dispatch action to store, and use state values instead of theirs local state.
2. Use Redux-Saga
- When dispatching an action for fetching content from API, Redux-Saga should be handling changing loading state, because it is considered as a side-effect of this action.
- Redux-Saga should call
fetch.service.js
functions. - Commit Point
3. Expand state
- Add count on top of the feed screen that represent number of fetched posts.
- This count should be available in Redux state and increased using
redux-saga
middleware. - Show this count number also in post screen.
- Commit Point
4. Favorites
- Add Favorites feature to app.
- Detail screen (post) should have a button that saves this post to favorites.
- Display a star in top right corner of the cell in feed screen that is saved in favorites.
- Add a filter option or new screen that displays only favorite posts from feed screen.
- Add feature to delete posts from favorites list
- Commit Point
Merge request
Estimate 2 days
Persist data
1. Persist state of the app between runs
- You may notice that with every fresh run or reload, the state is empty.
- Add
redux-persist
orrealm
to save state between runs. - Commit Point
Merge request
Estimate 1 day
Shake
- In DECODE, we develop a bug reporting tool Shake. To familiarize yourself with it, check Shake documentation and add the Shake SDK to the project (also, dogfooding doesn’t hurt 😄 ). The installation process is explained on the documentation setup page.
- Commit Point
Merge request
Estimate 1 day