Super Cool Blog Post
Posted: August 23, 2021

How To Create a React App Using CRA
Requirements
- NodeJS
- node version >= 8.10
- npm version >= 5.6
Content
Steps
INFO: The following steps installs basic CRA without redux. If you want redux (redux toolkit) installed by default, see the Install with Redux section.
Default Installation
- Run the command any of the commands. The following will use the yarn package manager if available. If you want to use npm, proceed to (b):
NOTE: It is highly recommended to use npm (b) over yarn to have a smooth custom eslint integration.
/* --- NPX --- */ npx create-react-app <YOUR_PROJECT_DIRECTORY> /* --- NPM --- */ npm init react-app my-app /* --- YARN --- */ yarn create react-app my-app
npm create-react-app my-app --use-npm
- Start the development:
npm start
(node)yarn start
(yarn)
- Build for production:
npm run build
(node)yarn build
(yarn)
- Add new modules:
npm i --save <MODULE_NAME>
(node)yarn add <MODULE_NAME>
(yarn)
Install with Redux
- Similar to the Default Installation steps #1 and #2, but install using the command:
npx create-react-app my-app --template redux --use-npm
Additional Configuration
Further configure the default CRA app into your development environment.
INFO: The following steps uses npm as package manager for CRA. Steps for yarn may vary.
Add ESLint
- Install the standard eslint dependencies for react.
- Using npm
npm i -D eslint eslint-config-standard eslint-plugin-import eslint-plugin-node eslint-plugin-promise eslint-plugin-standard eslint-config-standard-react eslint-plugin-react
- Using yarn
yarn add -D eslint eslint-config-standard eslint-plugin-import eslint-plugin-node eslint-plugin-promise eslint-plugin-standard eslint-config-standard-react eslint-plugin-react
- Using npm
- Add node_modules in the .gitignore file.
node_modules/
- Create npm scripts for linting and fixing.
"lint:fix": "eslint --fix <dir1> <dir2>", "lint": "eslint <dir1> <dir2>", /** eslint fix all js files */ "lint:fix": "eslint . --fix
NOTE: As of 20210414, add the ff. if you will encounter an error that refers to @typescript-eslint/parser, update the npm scripts:
eslint --ignore-path .gitignore --fix .
- Create a .eslintignore file inside the
<my-app>/src/ directory
and write here files or directories that you'd like to exclude from eslint. This is similar to .gitignore. - Create a .eslintrc.js file inside the
<my-app>/src/
directory:Import React from 'react' is no longer required if you are using React 17 or higher. Add the following in the eslintrc.js file:module.exports = { env: { browser: true, es6: true }, extends: [ 'standard', 'standard-react' ], globals: { Atomics: 'readonly', SharedArrayBuffer: 'readonly' }, parserOptions: { ecmaFeatures: { jsx: true }, ecmaVersion: 2018, sourceType: 'module' }, plugins: [ 'react', 'react-hooks' ], rules: { indent: ['error', 2], 'linebreak-style': ['error', 'unix'], quotes: ['error', 'single'], semi: ['error', 'never'] // 'no-unused-vars': 'off', // 'no-undef': 'off', // 'no-console': 2 } }
"rules": { ... 'react/jsx-uses-react': 'off', 'react/react-in-jsx-scope': 'off' }
- Run eslint fix.
npm run lint:fix
- Depending on your initial project set-up, you may need to:
- update all files to Unix LF endings
- update spacings
- Disable a lint rule inline via the codes i.e.,
/* eslint-disable no-unused-vars */ const ws = new WebsocketServer(server)
- Run linting
npm run lint
Install a Front-End Framework - Material UI
- Install material-ui.
- with npm:
npm install @material-ui/core
- with yarn:
yarn add @material-ui/core
- with npm:
- Use Roboto font from CDN, Copy the following into /public/index.html
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />
- (Optional) Install material-ui's pre-built SVG icons.
- with npm:
npm install @material-ui/icons
- with yarn:
yarn add @material-ui/icons
- with npm:
- Configure CRA to use material-ui themes. Create a simple theme file (theme.js)
import { createTheme } from '@material-ui/core/styles' const mainTheme = createTheme({ palette: { primary: { light: '#EDF1FA', main: '#31376D', dark: '#31376D', contrastText: '#FFFFFF' }, secondary: { light: '#999999', main: '#009688', dark: '#009688', contrastText: '#FFFFFF' }, text: { secondary: '#999999' }, background: { appBar: 'rgba(248, 249, 253, 0.35)' } } }) export default mainTheme
- Use the theme from #4 and other material-ui globals on index.js
import { ThemeProvider } from '@material-ui/core/styles' import CssBaseline from '@material-ui/core/CssBaseline' import mainTheme from './theme' ReactDOM.render( <React.StrictMode> <ThemeProvider theme={mainTheme}> <CssBaseline /> <App /> </ThemeProvider> </React.StrictMode>, document.getElementById('root') )
- Use material-ui on components.
import React from 'react' import Typography from '@material-ui/core/Typography' function HomePage () { return ( <Typography variant='h5'>Home</Typography> ) } export default HomePage
Configure Routing
- Install
react-router-dom
if it is not yet installed.npm install --save react-router-dom
- Create your react components.
- Create a routes.js file which references the components. For example:
import EmailContainer from './containers/email' import HomePage from './components/homepage' const routes = [ { path: '/email', isProtected: false, component: EmailContainer }, { path: '/', isProtected: false, component: HomePage } ] export default routes
- Update App.js to use react-router-dom's Router, Route and Switch components.
import React from 'react' import { BrowserRouter as Router, Route, Switch } from 'react-router-dom' import Navigation from './components/navigation' import routes from './routes' function App (props) { return ( <Router> <Navigation /> <Switch> {routes.map((entry, index) => (<Route exact path={entry.path} key={index} render={(props) => <entry.component {...props} title='Props through render' />} />))} </Switch> </Router> ) } export default App
Configure Redux
- If you installed CRA without redux, add redux (toolkit) to the existing CRA app.
- run:
npm install --save @reduxjs/toolkit react-redux
- run:
- Configure a redux state slice file, i.e., profile-slice.js for users profile.
import { createSlice } from '@reduxjs/toolkit' const profileSlice = createSlice({ name: 'profile', initialState: { loading: false, client_id: '', authState: '', lname: '', message: '', }, reducers: { setLoading (state, action) { return { ...state, loading: action.payload, error: '' } }, setError (state, action) { return { ...state, isLoading: false, error: action.payload } }, setMessage (state, action) { state.message = action.payload }, setAuthState (state, action) { state.authState= action.payload }, ... } }) export const { setLoading, setError, setMessage, setAuthState } = profileSlice.actions export default profileSlice.reducer export const setProfileError = (errorMsg) => dispatch => { dispatch(setError(errorMsg)) } export const getLiveMessage = () => async dispatch => { let msg try { dispatch(setLoading(true)) msg= await getOnlineEmail() } catch (err) { dispatch(setError(err.message)) } dispatch(setMessage(msg)) }
- Create a
rootReducers.js
file in /src/redux. Add profile-slice.js and other slices in the combineReducers part here.import { combineReducers } from 'redux' import profileReducer from '../containers/profile/profile-slice' const appReducer = combineReducers({ user: mainPageReducer }) const rootReducer = (state, action) => { if (state && state.user.authState === AUTH_STATE.SIGN_OUT) { // reset all reducers to their initial states. //Sign-out state detection may vary state = undefined } return appReducer(state, action) } export default rootReducer
- Create a
store.js
file in /src/redux. Add slice reducers here.import rootReducer from './rootReducer' import { configureStore } from '@reduxjs/toolkit' export const store = configureStore({ reducer: rootReducer })
- Update index.js to use redux.
// Redux import * as serviceWorker from './serviceWorker' import { Provider } from 'react-redux' import { store } from './redux/store' ReactDOM.render( <Provider store={store}> <ThemeProvider theme={outerTheme}> <CssBaseline /> <App /> </ThemeProvider> </Provider>, document.getElementById('root'))
- Use redux states in your container components.
import React, { useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { getLiveMessage, setMessage } from './profile-slice' function ProfileContainer () { const profile = useSelector((state) => state.profile) const dispatch = useDispatch() console.log(profile) useEffect(() => { dispatch(setMessage('hello, world!')) }, []) }
Configure Firebase
We are going to use the react-redux-firebase library to manage firebase. You can refer to the sample project for more information, or check out installation information from the tutorial getting started with react-redux-firebase.
- Install the following dependencies. Skip installation of dependencies which are already installed in your project.
npm install --save react-redux-firebase firebase npm install --save redux react-redux npm install --save redux-firestore@latest npm install react-router-dom
References
react
[1] - cra getting started
[2] - react router link
material-ui
[1] - theming