This application is a series of demos of various features of React that can help jump start an application. One can pick and choose from the features list for your apps needs.
- Install nvm
- Install the Node Version given in the
.nvmrc
file.
Chooses the version of node specified in the .nvmrc
Installs packages.
Runs the app in the development mode. Open http://localhost:3000 to view it in the browser.
The page will reload if you make edits. You will also see any lint errors in the console.
Launches the test runner in the interactive watch mode.
See the section about running tests for more information.
Builds the app for production to the build
folder.
It correctly bundles React in production mode and optimizes the build for the best performance.
The build is minified and the filenames include the hashes.
Your app is ready to be deployed!
One of the great things about a bundled build is you can host it on a simple AWS S3 bucket (or the equivalents for Azure, GCP). Saves you money on standing up a Linux server on EC2 etc.
Considered for future inclusion:
- ✓
Linting setup for IDEs (VSCode, Webstorm) - ✓
Router - ✓
React Helmet - ✓
Context API - ✓
react css modules - ✓
CSS classnames package - ✓
REST service call with fetch examples - ✓
Form validation with react-hook-form - ✓
Form validation with formik - ✓
Paginated tabular data with Material-UI - ✓
Adding a favicon - ✓
Redux - ✓
React App Anatomy - Express server with proxy
- infinite scroll widget
- SASS library
- Testing framework
BELOW HERE: added features
These packages are added to devDependencies
:
eslint, eslint-config-standard, eslint-config-standard-jsx, eslint-config-standard-react, eslint-plugin-import, eslint-plugin-json, eslint-plugin-n, eslint-plugin-node, eslint-plugin-promise, eslint-plugin-react, prettier
- Preferences -> Languages & Frameworks -> JavaScript -> Code Quality Tools -> ESLint
- Selecting the
Automatic ESLing Configuration
radio button should be sufficient - Check the box if you want ESLint fixing on save
If you would like a keystroke to fire off your ESLint fixing:
- Preferences -> Keymap -> Plugins -> Javascript and TypeScript, double-click on item "Fix ESLint Problems", select "Add Keyboard Shortcut" and type in your shortcut. Mine is ctrl-Shift-L.
The instructions below are incomplete and need to be improved by someone who knows VSCode well.
- In the left rail, click the Extensions icon
- In the search field, type eslint. The
ESLint
extension should come up. If not installed, press the blueInstall
button - Open VSCode settings (cmd-comma on a Mac). It the left rail, Open
Extensions
and click on ESLint. - Press the checkbox under
Eslint: Enable
- Under
Eslint: Run
select the onSave option.
The sequence of events when you launch the app with npm run start
is:
- index.html from the
public
folder is loaded. It renders a single <div> that is the container for the rest of the app. Webpack slighly modifies this file so that it also loads: src/index.js
. This will render the <App> component, which for us, lives insrc/containers/App/index.js
. But first:- Babel will convert it from
.jsx
to plain.js
first, so the friendly-looking <App> becomes a DOM command likeReact.createElement('DIV', etc. etc.)
. - Rinse and repeat for all the components under <App>.
React Routing is used throughout for defining 'pages' and generating links to them. It takes advantage of <NavLink>'s ability to style the currently selected link.
React CSS modules are used to namespace the CSS and prevent any component's styles from polluting the styles of others. CSS files become modules when you name them xxxx.module.css
. See the code for the convention of declaring and referencing your styles.
When you view the source, you will notice that the css class names and id's have been decorated with additional characters. Example: App_link__xYAAD
.
The classnames package is in use in the Paginated, Tabular Data
demo.
react-helmet-async
solves the inherent problem of SPAs where all 'pages' inherit the HTML <title> of the main App. Helmet allows you to set the title for each component individually. You would want to have a <Helmet> element for a component that has a route assigned to it, not to components instantiated by composition.
The original react-helmet
is buggy.
This app is using the widely-used approach of:
- Creating a folder for the component beginning lower case, e.g.
myComponent
- The file for the component itself is named
index.html
. The exported Component will begin upper case, e.g.MyComponent
This is by no means the universal approach, so considering others is certainly an option.
The demo Shared data via Context API
shows two unrelated components who have access to items from a Context API instance: some JSON data, and a method for rendering it. The title prefixes used by Helmet
are also obtained this way. The implementation steps are:
(1) Create StarterContext.js
(src/containers/App)
(2) In the App container, import it: `import { StarterProvider } from './StarterContext'
(3) In App's return value, wrap the HTML output with <StarterContext<:
<Router>
...other stuff here...
<StarterProvider>
...your HTML here...
</StarterProvider>
...
</Router>
(4) Repeat sep 2 for each component that needs the provider
(5) In each component retrieve the item you need: const { HTMLtitlePre } = useContext(StarterContext)
Context API is simpler and lighter weight than Redux for sharing read-only contents.
The Shared data via Context API
demonstrates this.
This is now part of the Shared data via Context API
demo.
All components and containers are function based, so any of them can support hooks.
The Shared data via Context API
demo uses the useEffect()
and useState()
hooks.
<App> and <ContextDemo> are designated as Containers because they compose Components inside them.
The library used for this demo is react-hook-form
.
This example uses material-react-table which is in
turn based on material-ui (a.k.a. MUI). The packages added to Dependencies
are:
@mui/material, @mui/icons-material, @emotion/react, @emotion/styled, material-react-table
An NTERSOL favicon as added, look for it in your browser tabs.
The approach was to take a small logo from Company Images
and pass it to the online Favicon Generator. The images it produced
were all copied into public
, they are:
android-chrome-192x192.png, favicon.ico, android-chrome-512x512.png, index.html, apple-touch-icon.png manifest.json favicon-16x16.png, favicon-32x32.png
...and these lines were added to public/index.html
:
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<LINK REL="SHORTCUT ICON" HREF="%PUBLIC_URL%/favicon.ico?v=2" type="image/x-icon" />
This demo uses the hooks version of Redux.
The packages added are:
react-redux, react-router-dom, redux, redux-thunk
The definition of the state we are managing in Redux resides in src/redux
. For further information, try Getting Started with Redux.
The top level App
component needs to be wrapped with <Provider>:
import { Provider } from 'react-redux'
import store from './redux/store'
...
<Provider store={store}>
<App />
</Provider>
Clients who need to read the Redux state:
import { useSelector } from 'react-redux'
...
const ourStore = useSelector(state => state.ourReducer)
const { ourValue }= ourStore.state
Clients who need to write the state:
import { useDispatch } from 'react-redux'
import { setGlobalState } from '../../redux/actions'
...
const dispatch = useDispatch()
const valueToSet = 'foo'
dispatch(setGlobalState({ state: { ourValue: valueToSet } }))
The names setGlobalState, state, ourStore, ourValue, etc. are all arbitrary and should be selected according to the meaning they have in your app.
This project was bootstrapped with Create React App.
It has not been ejected (read about ejecting here). One of the usual reasons for ejecting is to when a new feature requires a change to the webpack configuration. But alternatives to ejecting should be explored first.