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.
Would you really bootstrap a new client app with this code? Probably not, you'd run Create React App so you can customize it according to the needs from the get-go.
- 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.tsx
. This will render the <App> component, which for us, lives insrc/containers/App/index.tsx
. 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.
- Files and file folders should be all lower case with hyphens, ie "my-widget/my-widget.tsx". Some environments are case sensitive and this also prevents casing errors and makes imports from NPM more consistent
- Function components should be pascal case, ie "MyWidget"
- Methods should be camelCase and be named for this function, ie "addNumbers"
- Function filenames should match the folder filename, ie "my-widget/my-widget.tsx". This makes it easy to look up files via file search and also prevents having hundreds of "index.tsx" in the project which are indistinguishable
(1) Create StarterContext.tsx
(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
.
The same app above, written for the Formik library with Yup validation.
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 favicon as added, look for it in your browser tabs.
The approach was to take a small logo 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.