Skip to content

Instantly share code, notes, and snippets.

@AliAldobyan
Forked from khm56/Coded React Setup Guide.md
Created October 19, 2020 22:23
Show Gist options
  • Save AliAldobyan/3a8cfe465f780d48835b3dbaa6500f6d to your computer and use it in GitHub Desktop.
Save AliAldobyan/3a8cfe465f780d48835b3dbaa6500f6d to your computer and use it in GitHub Desktop.
FrontEnd Setup Guide
  • Setup a new React-App

     $ yarn create react-app <AppName>
  • Setup Bootstrap in your project

     $ yarn add bootstrap
    • In your index.js
       import "bootstrap/dist/css/bootstrap.min.css";
  • Setup Routers

     $ yarn add react-router-dom
    • In index.js
       import { BrowserRouter } from "react-router-dom";
      
    • Wrap your <App/> with <BrowserRouter>
       ReactDOM.render(
       	<BrowserRouter>
       		<App />
       	</BrowserRouter>,
       document.getElementById("root"));
    • In App.js
       import { Switch, Route, Redirect } from "react-router-dom";
    • In your return, your code should look something like the following
       <Switch>
       	<Redirect exact from="/" to="/authors" />
       	<Route path="/authors/:authorID" component={AuthorDetail} />
       	<Route
       	path="/authors/"
       	render={props => (
       	<AuthorsList {...props} authors={authors} />
       	)}
       	/>
       	<Route
       	path="/books/:bookColor?"
       	render={props => <BookList {...props} books={books} />}
       	/>
       </Switch>
    • To navigate to another Route in any of your components
      import {Link} from “react-router-dom”
    • Use the <Link> element like the following example
       <Link to="/authors/">Authors</Link>
  • Setup Redux

     $ yarn add redux
     $ yarn add react-redux
    • Create a folder named redux in your project
    • In your redux folder create 2 folders actions and reducers and an index.js file
  • Setup Your Actions

    • Create a file in your actions folder named actionTypes.js

    • Define your action Types in actionTypes.js like the following

       export const FETCH_AUTHORS = "FETCH_AUTHORS";
       export const FILTER_AUTHORS = "FILTER_AUTHORS";
       export const FETCH_AUTHOR_DETAIL = "FETCH_AUTHOR_DETAIL";
       export const SET_AUTHOR_LOADING = "SET_AUTHOR_LOADING";
       export const POST_AUTHOR = "POST_AUTHOR";
       export const POST_BOOK = "POST_BOOK";
       export const SET_ERRORS = "SET_ERRORS";
    • Create an instance.js file in your actions folder

       import axios from "axios";
       const instance = axios.create({
         baseURL: "https://the-index-api.herokuapp.com"
       });
       export default instance
    • Create your first action file e.g. authors.js

       import instance from "./instance"
       import {FETCH_AUTHORS, FILTER_AUTHORS} from "./actionTypes";
    • Define your functions for e.g.

       export const fetchAuthors = () => {
       	return async dispatch => {
       	try {
       		const res = await instance.get("/api/authors/");
       		const authors = res.data;
       		dispatch({ type: actionTypes.FETCH_AUTHORS, payload: authors });
       	}catch (err){
       		console.error(err);
       	}
       	};
       };

      Don’t forget to always dispatch to the reducer

    • Create as many action files as your project requires then create a file called ‘index.js’ in your ‘actions’ folder and export all

       export { fetchAuthorDetail, postBook } from "./author";
       export { fetchAuthors, filterAuthors, postAuthor } from "./authors";
       export { resetErrors } from "./errors";
  • Setup your Reducers

    • Create your Reducers in your reducers folder e.g. ‘authors.js`
    • Your reducer file should look something like the following
       import * as actionTypes from "../actions/actionTypes";
      
       const initialState = {
       authors: [],
       filteredAuthors: [],
       loading: true
       };
      
       const reducer = (state = initialState, action) => {
       switch (action.type) {
       	case actionTypes.FETCH_AUTHORS:
       	return {
       		...state,
       		authors: action.payload,
       		filteredAuthors: action.payload,
       		loading: false
       	};
      
       	case actionTypes.FILTER_AUTHORS:
       	return {
       		...state,
       		filteredAuthors: state.authors.filter(author => {
       		return `${author.first_name} ${author.last_name}`
       			.toLowerCase()
       			.includes(action.payload);
       		})
       	};
       	case actionTypes.POST_AUTHOR:
       	return {
       		...state,
       		authors: [action.payload].concat(state.authors)
       	};
       	default:
       	return state;
       }
       };
      
       export default reducer;
    • Create index.js in your reducers folder
    • In your reducers/index.js combine the reducers, create a store and export
       import { combineReducers} from "redux";
       //import your reducer files here like the following two lines
       import authorsReducer from "./authors";
       import authorReducer from "./author";
       const rootReducer = combineReducers({
       //the following two lines are an example
       rootAuthors: authorsReducer,
       rootAuthor: authorReducer
       });
      
      
       export default rootReducer;
    • Install redux-thunk
       $ yarn add redux-thunk
    • In your redux/index.js your code should look like the following example if you are using React if React native skip this step and loop at the final step in this section
       import { createStore, compose, applyMiddleware } from "redux";
       import thunk from "redux-thunk";
      
       import reducer from "./reducers";
      
       const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
      
       const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)));
      
       export default store;
    • In src/index.js, set up the App for redux:
       //You wont need this import if you are not using Routers
       import {BrowserRouter} from “react-router-dom”
       import { Provider } from "react-redux";
       // import your redux/index.js here (the store)
       import store from "./redux"
      
       ReactDOM.render(
       <Provider store={store}>
       	<BrowserRouter>
       		<App />
       	</BrowserRouter>
       </Provider>,
       document.getElementById("root")
       );
       registerServiceWorker();
    • If you are setting a React Native project insted of importing the Provider in index.js import Provider and Wrap the content of App.js with the provider
    • Calling States from the store in your components
       import {connect} from “react-redux”
    • Create a function named mapStateToProps under your component
       const mapStateToProps = state=>{
       	return {
       <GiveYourStateAName>: state.<reducerName>.<stateNameInReducer>
       	}
       }
    • Connect your component
       export default connect(mapStateToProps)(<ComponentName>)
    • Use the defined functions in your code
       props.<stateNameYouAssigned>
    • Calling functions from your actions in your components
       import {connect} from “react-redux”
       //Syntax
       import {<functionName>, <functionName>} from ./redux/actions”
       //Example
       import {getAuthors} from "./redux/actions"
       //Make sure the functions are exported in your actions’ index.js file
    • Create a function named mapDispatchToProps under your component
       const mapDispatchToProps = dispatch=>{
       	return {
       		//Syntax
       <GiveYourFunctionAName>: (<parametersExpected>) => dispatch(<functionName>(parametersExpected));
       getAuthors : () => dispatch(getAuthors())
      
       	}
       }
    • Connect your component
       export default connect(null,mapDispatchToProps)(<ComponentName>)
    • Use the defined states in your code
       props.getAuthors()
  • Setup React DevTools for React Native:

    • Install
       $ yarn add redux-devtools-extension
    • In redux/index.js it should look like that:
       import { createStore, combineReducers, applyMiddleware } from "redux";
       import thunk from "redux-thunk";
       import { composeWithDevTools } from "redux-devtools-extension";
       //Import your root reducer here
       import reducers from "./reducers";
      
       const middlewares = [thunk];
       const enhancer = composeWithDevTools({
         // Options: https://github.com/jhen0409/react-native-debugger#options
       })(applyMiddleware(...middlewares));
      
       const store = createStore(reducers, enhancer);
      
       export default store;
      Then Enable Debug JS in your expo app (Phone/Simulator)
  • Setup Axios

    • Install
       $ yarn add axios
    • Import
       import axios from "axios"
  • Setup Authentication

    • Install

       $ yarn add jwt-decode
    • Import jwt_decode

       import jwt_decode from "jwt-decode";
    • Define your Sign Up and Login functions for example

       export const login = userData => {
       return async dispatch => {
       	try {
       	const res = await axios.post(
       		"https://precious-things.herokuapp.com/login/",
       		userData
       	);
       	const user = res.data;
       	dispatch(setCurrentUser(user.token));
       	} catch (err) {
       	console.error(err);
       	}
       };
       };
    • Set the user in the reducer by defining the following function

       const setCurrentUser = token => {
       let user;
       if (token) {
       	localStorage.setItem("token", token);
       	axios.defaults.headers.common.Authorization = `jwt ${token}`;
       	user = jwt_decode(token);
       } else {
       	localStorage.removeItem("token");
       	delete axios.defaults.headers.common.Authorization;
       	user = null;
       }
      
       return {
       	type: SET_CURRENT_USER,
       	payload: user
       };
       };

      Don't forget to define SET_CURRENT_USER in your actionTypes.js and import it

    • Your auth reducer should look something like the following

       import { SET_CURRENT_USER } from "../actions/actionTypes";
      
       const initialState = null;
      
       export default (state = initialState, action) => {
       switch (action.type) {
       	case SET_CURRENT_USER:
       	return action.payload;
      
       	default:
       	return state;
       }
       };
    • Define a Logout Function that will call setCurrentUser

       export const logout = () => setCurrentUser();
    • Define a function in your actions to check if user is logged in

       export const checkForExpiredToken = () => {
         // Check for token expiration
         const token = localStorage.getItem("token");
         let user = null;
         if (token) {
           const currentTimeInSeconds = Date.now() / 1000;
      
           // Decode token and get user info
           user = jwt_decode(token);
      
           // Check token expiration
           if (user.exp >= currentTimeInSeconds) {
             // Set user
             return setCurrentUser(token);
           }
         }
         return logout();
       };
    • Define the Sign Up function

       export const signup = userData => {
       return dispatch => {
       	try {
       	const res = await axios.post(
       		"https://precious-things.herokuapp.com/signup/",
       		userData
       	)
       	//If your backend logs the user in when signing up use the following code
       	const user = res.data;
       	dispatch(setCurrentUser(user.token));
       	//If it doesn't log you in 
       	dispatch(login(userData));
       	} catch (err) {
       	console.error(err)
       	}
       };
       };
    • To have persistent login, Go to your redux/index.js and call checkForExpiredToken

       import {checkForExpiredToken} from "./redux/actions"
       //After defining the store use the following code to call checkForExpiredToken
       store.dispatch(checkForExpiredToken())
  • Setup React Native:

    • One time setup on your device:
       $ yarn global add expo-cli
    • To create a new React Native project:
       expo-client init <appName>
      Then choose the blank option
    • Add Native Base to your project
       $ yarn add native-base
    • Icon sources urls
       https://oblador.github.io/react-native-vector-icons/
       https://expo.github.io/vector-icons/
      
      To use the Icons
       <Icon type="FontAwesome" name="iconName"/> 
  • Setup Navigation:

    • Run the following command
       $ yarn add react-navigation
    • Install the following dependencies:
       expo install react-native-gesture-handler react-native-reanimated
    • Create folder in your project named Navigation
  • Setup a Stack Navigator:

    • Run the following commamd
       $ yarn add react-navigation-stack
    • Create a file in your Navigation folder named MyStackNav.js your file should look something like the following example
       //import createStackNavigator 
       import { createStackNavigator } from "react-navigation-stack";
       // import your components here they should be full screens 
       import Home from "../Components/Home";
       import List from "../Components/List";
       import Detail from "../Components/Detail";
      
       const MyStackNav = createStackNavigator(
         {
         //give names to your components that you will be using throughout your project
           HomeScreen: Home,
           ListScreen: List,
           DetailScreen: Detail
         },
         {
         //define the intial component when the app runs
           initialRouteName: "HomeScreen"
         }
       );
      
       export default MyStackNav;
    • Create an index.js file in your Navigation Folder like the following example:
       import { createAppContainer } from 'react-navigation';
       import MyStackNav from "./MyStackNav.js";
      
       const AppContainer = createAppContainer(MyStackNav);
      
       export default AppContainer;
    • Import your AppContainer in App.js and render it
       import AppContainer from "./Navigation/AppContainer";
      
       export default Funtion App() {
           return <AppContainer />;
       }
    • To navigate between screens look at the following examples:
       <Button onPress={() => props.navigation.navigate("List")}>
         <Text>GO TO LIST PAGE</Text>
       </Button>
       <Button onPress={() => props.navigation.goBack()}>
         <Text>GO TO LIST PAGE</Text>
       </Button>
       <Button onPress={() => props.navigation.push("Home)}>
         <Text>GO TO LIST PAGE</Text>
       </Button>
    • To pass parameters while navigation:
       <ListItem
           onPress={() =>
             props.navigation.navigate("Detail", {
       	itemID: oneItem.id,
       	anotherParam: "some random text"
             })
           }
         >
           <Text>{oneItem.name}</Text>
         </ListItem>
         ```
    • To access parameters:
       const passedItemID = props.navigation.getParam("itemID", 1);
      		const anotherParam = props.navigation.getParam("anotherParam", "some default text");
  • Setup a BottomTabNavigator:

    • Install

       $ yarn add react-navigation-tabs
    • Create Your different Stack Navigators in your Nvigation Folder

    • Create a BottomTabNav.js file and do the following:

       import { createBottomTabNavigator } from "react-navigation-tabs";
       //Import your stacks
       import ProductStackNav from "./ProductStackNav";
       import ProfileStackNav from "./ProfileStackNav";
       
       const BottomTabNav = createBottomTabNavigator({
         Products: ProductStackNav,
         Profile: ProfileStackNav
       });
      
       export default BottomTabNav;
    • In your Navigation/index.js do the following:

       import { createAppContainer } from "react-navigation";
       import BottomTabNav from "./BottomTabNav";
      
       const AppContainer = createAppContainer(BottomTabNav);
      
       export default AppContainer;
      
    • Then render the AppContainer in your App.js Component

  • Style your Headers

    • In your createStackNavigator function (in every stack) you can customize the following
       const MyStackNav = createStackNavigator(
         {
           ...
         },
         {
           initialRouteName: "Home",
           defaultNavigationOptions: {
             headerTintColor: "white",
             headerStyle: {
       	backgroundColor: "#90d4ed"
             },
             headerTitleStyle: {
       	fontWeight: "bold"
             }
          }
         }
       );
  • To Customize your header in a component

    • After defining your component and before exporting call the navigationOptions with the needed configuration:
       const Home = props => {
           //Code here
       }
      
       Home.navigationOptions = {
         title: "Home",
         headerRight: (
           <Button title="Press Me" color="white" onPress={() => alert("HELLO!")} />
         ),
         headerStyle: {
           backgroundColor: "white"
         },
         headerTintColor: "black"
       };
       export default Home;
    • To use navigation in the header we need to pass it navigationOptions example:
       Detail.navigationOptions = ({ navigation }) => {
         const itemID = navigation.getParam("itemID");
         return {
           title: items.find(item => item.id === itemID).name
         };
       };
    • To Interact with the header look at the following example:
       <Button
         onPress={() => props.navigation.setParams({ name: "Lailz" })}
         title="Set title name to 'Lailz'"
       />
       Home.navigationOptions = ({ navigation }) => {
         return {
           title: navigation.getParam("name")
         };
       };
      Because props cannot be accessed in navigationOptions
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment