-
So we are building Airbnb Clone in React Native.
-
I am studying this tutorial by cubui
-
The complete playlist is available below:
-
My system:
- Windows 10
- react-native-cli: 2.0.1
- react-native: 0.57.5
-
Creating a new application from CLI:
- react-native init AirbnbClone
- For more basics:
I came across this same problem, and the above answer didn't work for me because github was being fed my credentials through windows credential manager instead of git bash.
You may have to check windows credential manager and delete the github entry under control panel > user accounts > credential manager > Windows credentials > Generic credentials
- NOTES:
- Have a directory structure first.
- It's always recommended to have an UI design build before coding.
- Strat with a LoggedOut screen first.
- CSS z-index Property:
- The z-index property specifies the stack order of an element.
- An element with greater stack order is always in front of an element with a lower stack order.
- Note:
- z-index only works on positioned elements (position:absolute, position:relative, or position:fixed).
- Let's first start by creating dir structure:
- root:
- src
- containers
- components
- buttons
- RoundedButtons.js
- buttons
- styles
- colors
- index.js
- colors
- screens
- LoggedOut.js
- img
- airbnb-logo.png
- src
- root:
- Install react-native-vector-icons
- Run react-native link in Project CLI after installation.
- Restart the current running server.
- To use Icons from FontAwesome:
- Import Icons from react-native-vector-icons/dist/FontAwesome
- Home Screen:
- Facebook Button Press:
- Create Account Button Press:
- Adding to directory structure:
- root:
- src
- containers
- components
- buttons
- RoundedButtons.js
- NextArrowButton.js
- form
- InputField.js
- buttons
- styles
- colors
- index.js
- colors
- screens
- LoggedOut.js
- LogIn.js
- img
- airbnb-logo.png
- src
- root:
- Add a new screen LogIn.js
- Create set of form components.
- Log In Screen:
3: Airbnb Clone using React Native - Fix button hidden by keyboard and add password toggler
- Note:
- Working of Show Password Button;
- Logic of show password is in it's InputField Component.
- If the input type is "password" we are showing the SHOW/HIDE button.
- The value of secureTextEntry for TextInput depends on "secureInput".
- The value of secureInput is set in the Component state.
- Which have a default boolean value depending on inputType.
- Everytime toggleShowPassword is called, the value of secureInput is changed.
- Working of Show Password Button;
- Floating Next Button:
- Show Password:
- Handle Next Button:
- Adding to directory structure:
- root:
- src
- containers
- components
- buttons
- RoundedButtons.js
- NextArrowButton.js
- form
- InputField.js
- Notification.js
- buttons
- styles
- colors
- index.js
- colors
- screens
- LoggedOut.js
- LogIn.js
- img
- airbnb-logo.png
- src
- root:
- Let's build an Error message screen.
-
No there was no ScrollView error, it's just that iOS and Android and diffrent UX.
-
Error Screen:
- Error-Free Screen:
- Entering Value:
- Entering Wrong Value:
- Adding to directory structure:
- root:
- src
- containers
- components
- buttons
- RoundedButtons.js
- NextArrowButton.js
- form
- InputField.js
- Notification.js
- Loader.js
- buttons
- styles
- colors
- index.js
- colors
- screens
- LoggedOut.js
- LogIn.js
- img
- airbnb-logo.png
- src
- root:
- By default the Gif images are not supported in android react native app.
- You need to set use Fresco to display the gif images.
- Edit your android/app/build.gradle file and add the following code:
compile 'com.facebook.fresco:animated-gif:1.10.0' compile "com.facebook.fresco:animated-base-support:1.3.0" // (Only if supporting WebP.) compile 'com.facebook.fresco:animated-webp:1.10.0' compile 'com.facebook.fresco:webpsupport:1.10.0'
- Then you need to bundle the app again;
- You can display the gif images in two ways like this.
<Image source={require('./../images/load.gif')} style={{width: 100, height: 100 }}/> <Image source={{uri: 'http://www.clicktorelease.com/code/gif/1.gif'}} style={{width: 100, height:100 }}/>
- You need to set use Fresco to display the gif images.
- Loader on handleNextButton:
-
We'll add an animated checkmark when the input field has a valid value.
-
Let's change the keyboard if the input field is an email.
-
Animated Checkmark:
- Adding to directory structure:
- root:
- src
- containers
- components
- buttons
- RoundedButtons.js
- NextArrowButton.js
- form
- InputField.js
- Notification.js
- Loader.js
- buttons
- styles
- colors
- index.js
- colors
- screens
- LoggedOut.js
- LogIn.js
- ForgotPassword.js
- img
- airbnb-logo.png
- src
- root:
- Forgot Password Screen:
- Entering Value:
- Entering Wrong Value:
- npm install --save:
- react-redux
- redux
- redux-logger
- redux-thunk
- I guess, I issue was the my node_module was turned to read only.
- So I,
- Closed my VS code.
- deleted node_module
- If script is not deleting, restart the system.
- Run "npm install"
- Retry installing the packages, (It worked.)
- Restart your server.
- Add to directory structure.
- root:
- src
- containers
- components
- buttons
- RoundedButtons.js
- NextArrowButton.js
- form
- InputField.js
- Notification.js
- Loader.js
- buttons
- styles
- colors
- index.js
- colors
- screens
- LoggedOut.js
- LogIn.js
- ForgotPassword.js
- img
- airbnb-logo.png
- redux
- store.js
- Here Reducers, Logger, ThunkMiddleware are imported, Logger is setup, Compose and ApplyMiddleware are used to setup all the middleware and then Store is created.
- reducer
// Very confusing, I might improvise latter.
- loggedOut.js
- Here createReducer() is imported from helper, also all the action Types are imported. Create reducer is passed empty state & type of action.
- index.js
- Here Combine Reducer is used to Combine all reducers exported from respective files.
- loggedOut.js
- action
- types.js
- Simple action types.
- loggedOut.js
- Login action
- index.js
- Combine all actions.
- types.js
- helpers
- createReducer.js
- Returns a function which setups reducer.
- createReducer.js
- store.js
- data
- user.json
- App.js
- Store is passed down to the application here.
- src
- root:
In my case the issue was that the emulator was making a request to:
http://10.0.2.2:8081/debugger-ui
instead of:
http://localhost:8081/debugger-ui and the request was failing.
To solve the issue: Before enabling remote debugging on your emulator, open http://localhost:8081/debugger-ui in chrome. Then enable remote debugging and go back to the chrome page where you should see your console logs.
- Nothing to show but yeah the syntax was kinda confusing, I just might simplify it latter.
- 'Provider' from react-redux will pass the 'store' to the application in App.js.
- 'store' is created by 'configureStore' CUSTOME FUNCTION in 'store.js'.
- Empty object is passed to 'configureStore'.
- Then 'createStore' from 'redux' is used to create store, and is passed 'reducer', 'initialState' (which is empty) and 'enhancer'.
- 'enhancer', CUSTOME FUNCTION uses 'compose' and 'applyMiddleware' to add middleware to store.
- Then 'createStore' from 'redux' is used to create store, and is passed 'reducer', 'initialState' (which is empty) and 'enhancer'.
- Empty object is passed to 'configureStore'.
- 'reducer' uses 'combineReducers' from 'redux' to combine all the reducers inported.
- Any reducers imports 'createReducer' from helper and 'action types'.
- Then specify the chance of state on a perticular action type.
- 'createReducer' is a CUSTOME FUNCTION which takes, 'initial state, and handler to distingise between action types.
- Then specify the chance of state on a perticular action type.
- 'types.js' is used to declare action types.
- Any component uses Redux as follow:
- Store is passed from 'App.js'.
- The component imports:
- 'connect' from 'react-redux'.
- Connect is used to 'map state to props', which is passed 'state' and 'map dispatch to prop', which is passed state using bindActionCreator.
- 'bindActionCreaators' from 'redux'.
- Is used to bind all the actions created by 'ActionCreators' with dispacth and later maped to props.
- So the component can use the functions in the component from 'props'.
- Is used to bind all the actions created by 'ActionCreators' with dispacth and later maped to props.
- CUSTOME FUNCTION 'ActionCreators' from 'redux/action'.
- Combines all the actions.
- 'connect' from 'react-redux'.
- Every action is passed dispatched which is then used to chance state.
Note: WARNING: Configuration 'compile' is obsolete and has been replaced with 'implementation' and 'api'.
- We'll connect everything.
- Using react-nativation and react-navigation-redux-helper to connect the navigation to the redux store.
- react-navigation-redux-helper:
- How it works:
- Any navigator can be passed a navigation prop to turn it into a "controlled" component, which defers state management to its parent. This mechanism is used in React Navigation to nest navigators, but it can also be used to customize state management.
- A Redux middleware is used so that any events that mutate the navigation state properly trigger React Navigation's event listeners.
- Finally, a reducer enables React Navigation actions to mutate the Redux state.
- Note:
- Most projects that are using both Redux and React Navigation don't need this library.
- And passing navigation to the root navigator means that you will have to handle state persistance and BackHandler behavior yourself.
- How it works:
-
npm install:
- react-navigation
- react-navigation-redux-helpers
-
Restart the server.
-
Add to directory structure.
- root:
- src
- containers
- components
- buttons
- RoundedButtons.js
- NextArrowButton.js
- NavBarButton.js
- form
- InputField.js
- Notification.js
- Loader.js
- buttons
- styles
- colors
- index.js
- navigator.js
- colors
- screens
- LoggedOut.js
- LogIn.js
- ForgotPassword.js
- img
- airbnb-logo.png
- redux
- store.js
- reducer
- loggedOut.js
- index.js
- navigation.js
- action
- types.js
- loggedOut.js
- index.js
- helpers
- createReducer.js
- data
- user.json
- navigators
- AppNavigator.js
- AppRouteConfigs.js
- App.js
- src
- root:
-
We will have two navigators. One-stack navigator-which will takre care of the navigation for when the user is loged out. The other-tab navigator-which will be used once the user logged in.
-
Now let's create a reducer which we will use to chance screen.
-
Let's add the app navigator.
-
We will need to add the react navigation redux middleware in store.
- To dissable yellow waring:
- console.disableYellowBox = true;
- In App.js before App class.
- To dissable yellow waring:
-
Style the Top bar:
- create a NavBar button Component.
- Need to style the header for every screen.
- I just completely refactor the code for redux for my convinience.
- remove node_modules and package-lock.json
- npm install --save react-native-gesture-handler
- react-native link
Error: Native module com.oblador.vectoricons.VectorIconsModule tried to override com.oblador.vectoricons.VectorIconsModule for module name RNVectorIconsModule. Check the getPackages() method in MainApplication.java, it might be that module is being created twice.
I solve the issue modifying the MainActivity.java file. Vector module was declarated several time. Just remove the import and it works
- Much better so I did the following this specifically:
- Moved the store to seperate file.
- Simplify the syntax of action and reducer.
- Placed header on all the 3 screen we currently have.
- Added styles.
- Navigation button.
- Logged Out Screen:
- Log In Screen:
- Forgot Password Screen:
- In this section we'll create the Logged In screen which will contain the tab navigator.
-
Add to directory structure.
- root:
- src
- containers
- ExploreContainer.js
- SavedContainer.js
- ProfileContainer.js
- TripsContainer.js
- InboxContainer.js
- components
- buttons
- RoundedButtons.js
- NextArrowButton.js
- NavBarButton.js
- form
- InputField.js
- Notification.js
- Loader.js
- buttons
- styles
- colors
- index.js
- navigator.js
- colors
- screens
- LoggedOut.js
- LogIn.js
- ForgotPassword.js
- LoggedIn.js
- img
- airbnb-logo.png
- redux
- store.js
- reducer
- loggedOut.js
- index.js
- navigation.js
- action
- types.js
- loggedOut.js
- index.js
- helpers
- createReducer.js
- data
- user.json
- navigators
- AppNavigator.js
- AppRouteConfigs.js
- LoggedInTabsNavigator.js
- containers
- App.js
- src
- root:
-
Style all the currently created Tabs.
-
For Ionicons:
- Import:
- import Icon from 'react-native-vector-icons/Ionicons';
- Find: https://ionicons.com/
- Import:
-
Change to this screen when we log in.
-
Disable the back button so that user can'r go back to login screen after Logging in.
- Logged In Screen:
- In this section we'll build the notifications screen which will show for the first time users when they log in.
- Add to directory structure.
- root:
- src
- containers
- ExploreContainer.js
- SavedContainer.js
- ProfileContainer.js
- TripsContainer.js
- InboxContainer.js
- components
- buttons
- RoundedButtons.js
- NextArrowButton.js
- NavBarButton.js
- form
- InputField.js
- Notification.js
- Loader.js
- buttons
- styles
- colors
- index.js
- navigator.js
- colors
- screens
- LoggedOut.js
- LogIn.js
- ForgotPassword.js
- LoggedIn.js
- TurnOnNotification.js
- img
- airbnb-logo.png
- redux
- store.js
- reducer
- loggedOut.js
- index.js
- navigation.js
- action
- types.js
- loggedOut.js
- index.js
- helpers
- createReducer.js
- data
- user.json
- navigators
- AppNavigator.js
- AppRouteConfigs.js
- LoggedInTabsNavigator.js
- containers
- App.js
- src
- root:
- Turn On Notifications Screen:
-
Add to directory structure.
- root:
- src
- containers
- ExploreContainer.js
- SavedContainer.js
- ProfileContainer.js
- TripsContainer.js
- InboxContainer.js
- components
- SearchBar.js
- explore
- Categories.js
- Listings.js
- buttons
- RoundedButtons.js
- NextArrowButton.js
- NavBarButton.js
- form
- InputField.js
- Notification.js
- Loader.js
- styles
- colors
- index.js
- navigator.js
- colors
- screens
- LoggedOut.js
- LogIn.js
- ForgotPassword.js
- LoggedIn.js
- TurnOnNotification.js
- img
- airbnb-logo.png
- redux
- store.js
- reducer
- loggedOut.js
- index.js
- navigation.js
- action
- types.js
- loggedOut.js
- index.js
- helpers
- createReducer.js
- data
- user.json
- Categories.js
- navigators
- AppNavigator.js
- AppRouteConfigs.js
- LoggedInTabsNavigator.js
- containers
- App.js
- src
- root:
-
Starting with Search component.
- Explore Container Part 1:
- We will build the list of listtings.
- We have 2 types:
- Experiences
- Popular Reservations.
- They contain different elements:
- Experiences has a star rating.
- Favorite icon.
- We have 2 types:
- Add to directory structure.
- root:
- src
- containers
- ExploreContainer.js
- SavedContainer.js
- ProfileContainer.js
- TripsContainer.js
- InboxContainer.js
- components
- SearchBar.js
- explore
- Categories.js
- Listings.js
- buttons
- RoundedButtons.js
- NextArrowButton.js
- NavBarButton.js
- form
- InputField.js
- Notification.js
- Loader.js
- styles
- colors
- index.js
- navigator.js
- colors
- screens
- LoggedOut.js
- LogIn.js
- ForgotPassword.js
- LoggedIn.js
- TurnOnNotification.js
- img
- airbnb-logo.png
- redux
- store.js
- reducer
- loggedOut.js
- index.js
- navigation.js
- action
- types.js
- loggedOut.js
- index.js
- helpers
- createReducer.js
- data
- user.json
- Categories.js
- listings.js
- navigators
- AppNavigator.js
- AppRouteConfigs.js
- LoggedInTabsNavigator.js
- containers
- App.js
- src
- root:
- Explore Container Part 2:
- Continue styling rest of the Explore tab.
- There are two types of heading:
- Regular
- Bold
- Add to directory structure.
- root:
- src
- containers
- ExploreContainer.js
- SavedContainer.js
- ProfileContainer.js
- TripsContainer.js
- InboxContainer.js
- components
- Stars.js
- SearchBar.js
- explore
- Categories.js
- Listings.js
- buttons
- RoundedButtons.js
- NextArrowButton.js
- NavBarButton.js
- HeartButton.js
- form
- InputField.js
- Notification.js
- Loader.js
- styles
- colors
- index.js
- navigator.js
- colors
- screens
- LoggedOut.js
- LogIn.js
- ForgotPassword.js
- LoggedIn.js
- TurnOnNotification.js
- img
- airbnb-logo.png
- redux
- store.js
- reducer
- loggedOut.js
- index.js
- navigation.js
- action
- types.js
- loggedOut.js
- index.js
- helpers
- createReducer.js
- data
- user.json
- Categories.js
- listings.js
- navigators
- AppNavigator.js
- AppRouteConfigs.js
- LoggedInTabsNavigator.js
- containers
- App.js
- src
- root:
- Star Rating and Favourite Components:
- There is no button from the Login screen to go to Forgot Password screen.
- Color of the Status bar. (iOS)
- First let's make it white by default instead of black.
- Edit: root\ios\AirbnbClone\Info.plist
- Add:
</array> <key>UIViewControllerBasedStatusBarAppeareance</key> <true/> </dist>
- Then add StatusBar.setBarStyle('dark-content', true); in the desired places.
- Edit: root\ios\AirbnbClone\Info.plist
- First let's make it white by default instead of black.
- Since I am not using react-navigation-redux-helper and this is for my Android. I am skipping over it.
- Since android has a seperate StatusBar from the screen.
- Things to fix:
- Big Screen: Notification, Categories list.
- Small Screen: Text on Logged Out screen, Categories list .
-
Add to directory structure.
- root:
- src
- helpers
- utils.js
- containers
- ExploreContainer.js
- SavedContainer.js
- ProfileContainer.js
- TripsContainer.js
- InboxContainer.js
- components
- Stars.js
- SearchBar.js
- explore
- Categories.js
- Listings.js
- buttons
- RoundedButtons.js
- NextArrowButton.js
- NavBarButton.js
- HeartButton.js
- form
- InputField.js
- Notification.js
- Loader.js
- styles
- colors
- index.js
- navigator.js
- colors
- screens
- LoggedOut.js
- LogIn.js
- ForgotPassword.js
- LoggedIn.js
- TurnOnNotification.js
- img
- airbnb-logo.png
- redux
- store.js
- reducer
- loggedOut.js
- index.js
- navigation.js
- action
- types.js
- loggedOut.js
- index.js
- helpers
- createReducer.js
- data
- user.json
- Categories.js
- listings.js
- navigators
- AppNavigator.js
- AppRouteConfigs.js
- LoggedInTabsNavigator.js
- helpers
- App.js
- src
- root:
-
First we'll create a utility function to determine what phone we're using.
- We'll create the No Result component for the Saved tab.
- Add to directory structure.
- root:
- src
- helpers
- utils.js
- containers
- ExploreContainer.js
- SavedContainer.js
- ProfileContainer.js
- TripsContainer.js
- InboxContainer.js
- components
- saved
- NoResults.js
- Stars.js
- SearchBar.js
- explore
- Categories.js
- Listings.js
- buttons
- RoundedButtons.js
- NextArrowButton.js
- NavBarButton.js
- HeartButton.js
- form
- InputField.js
- Notification.js
- Loader.js
- saved
- styles
- colors
- index.js
- navigator.js
- colors
- screens
- LoggedOut.js
- LogIn.js
- ForgotPassword.js
- LoggedIn.js
- TurnOnNotification.js
- img
- airbnb-logo.png
- redux
- store.js
- reducer
- loggedOut.js
- index.js
- navigation.js
- action
- types.js
- loggedOut.js
- index.js
- helpers
- createReducer.js
- data
- user.json
- Categories.js
- listings.js
- navigators
- AppNavigator.js
- AppRouteConfigs.js
- LoggedInTabsNavigator.js
- helpers
- App.js
- src
- root:
- No Results Component for Saved Screen:
- Remove ugly buttons on press in Logged Out Screen.
- Replace TouchableHighlight for TouchableOpacity.
- We need to chance how much opacity to use.
- Put whole screen inside a ScrollView because Android has all kind of devices compared to iPhone. We want to make sure the user can see everything.
-
Add to directory structure.
- root:
- src
- helpers
- utils.js
- containers
- ExploreContainer.js
- SavedContainer.js
- ProfileContainer.js
- TripsContainer.js
- InboxContainer.js
- components
- saved
- NoResults.js
- Stars.js
- SearchBar.js
- explore
- Categories.js
- Listings.js
- buttons
- RoundedButtons.js
- NextArrowButton.js
- NavBarButton.js
- HeartButton.js
- form
- InputField.js
- Notification.js
- Loader.js
- saved
- styles
- colors
- index.js
- navigator.js
- colors
- screens
- CreateList.js
- LoggedOut.js
- LogIn.js
- ForgotPassword.js
- LoggedIn.js
- TurnOnNotification.js
- img
- airbnb-logo.png
- redux
- store.js
- reducer
- loggedOut.js
- index.js
- navigation.js
- action
- types.js
- loggedOut.js
- index.js
- helpers
- createReducer.js
- data
- user.json
- Categories.js
- listings.js
- navigators
- AppNavigator.js
- AppRouteConfigs.js
- LoggedInTabsNavigator.js
- helpers
- App.js
- src
- root:
-
Update the navigation from like button to screen.
- Similar to the example above where a stack contains a tab navigator, we can solve this in two ways: add navigationOptions to our tab navigator to set the tab bar to hidden depending on which route is active in the child stack, or we can move the tab navigator inside of the stack.
Imagine the following configuration:
const FeedStack = createStackNavigator({
FeedHome: FeedScreen,
Details: DetailsScreen,
});
const TabNavigator = createBottomTabNavigator({
Feed: FeedStack,
Profile: ProfileScreen,
});
const AppNavigator = createSwitchNavigator({
Auth: AuthScreen,
Home: TabNavigator,
});
If we want to hide the tab bar when we navigate from the feed home to a details screen without shuffling navigators, we cannot set the tabBarVisible: false configuration in navigationOptions on DetailsScreen, because those options will only apply to the FeedStack. Instead, we can do the following:
const FeedStack = createStackNavigator({
FeedHome: FeedScreen,
Details: DetailsScreen,
});
FeedStack.navigationOptions = ({ navigation }) => {
let tabBarVisible = true;
if (navigation.state.index > 0) {
tabBarVisible = false;
}
return {
tabBarVisible,
};
};
- Creating List Screen:
- Start by adding Title input filed. We can reuse the one from Login Screen.
- But need to make it flexible.
- Create a new form component:
- Add to directory structure.
- root:
- src
- helpers
- utils.js
- containers
- ExploreContainer.js
- SavedContainer.js
- ProfileContainer.js
- TripsContainer.js
- InboxContainer.js
- components
- saved
- NoResults.js
- Stars.js
- SearchBar.js
- explore
- Categories.js
- Listings.js
- buttons
- RoundedButtons.js
- NextArrowButton.js
- NavBarButton.js
- HeartButton.js
- form
- InputField.js
- RadioInput.js
- Notification.js
- Loader.js
- saved
- styles
- colors
- index.js
- navigator.js
- colors
- screens
- CreateList.js
- LoggedOut.js
- LogIn.js
- ForgotPassword.js
- LoggedIn.js
- TurnOnNotification.js
- img
- airbnb-logo.png
- redux
- store.js
- reducer
- loggedOut.js
- index.js
- navigation.js
- action
- types.js
- loggedOut.js
- index.js
- helpers
- createReducer.js
- data
- user.json
- Categories.js
- listings.js
- navigators
- AppNavigator.js
- AppRouteConfigs.js
- LoggedInTabsNavigator.js
- helpers
- App.js
- src
- root:
- Public Radio Button:
- Private Radio Button:
- Create List Screen .
- Disabled buttom when no text.
- Loading.
- In this section we'll add apollo to the react native app and try to get some listings from the simple qraphql backend we created.
- First we need to ad couple of dependencies.
- Let's start the server and run the backend containers.
- Integrate apollo into our application.
-
Adding to dir:
- root
- src
- config
- index.js
- config
- src
- root
-
Add apollo provider in App.js
-
Now let's see if we can run somr GraphQL queries to fetch some listings.
-
GraphQL Queries:
- Get lists.
query { multipleListings { id, title, description } }
- Mutation addListing:
mutation addListing { addListing(data: { title: "My fourth listing", description: "Sample description" }) { title, description } } //... till fourth
- Let's try to fetch the list inside the app.
- ExploreContainer.js
- Check data avilability in the app.