To install required libraries:
npm install --save-dev @babel/core @babel/cli @babel/preset-env @babel/preset-react
To add ES6 transpile, add .babelrc file:
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
First install webpack and relevant dependencies:
npm install --save-dev webpack webpack-cli webpack-dev-server style-loader css-loader babel-loader
To add webpack.config file:
- webpack.config uses ES5 javascript syntax
- webpack uses loaders to transpile our code for example to transform ES6 to regular javascript webpack uses 'babel-loader', similarly, for css styles uses 'style-loader', 'css-loader'
After adding webpack configuration to run your webpack dev server run:
npx webpack-dev-server --mode development
To automatically refresh page after each changes:
npm install --save-dev react-hot-loader
Then import and use in App.js as follow:
import { hot } from 'react-hot-loader';
...
export default hot(module)(App);
-
To install Redux:
npm install redux react-redux
-
Create store.js file inside src folder
-
Wrap App component in index.js with Provider from redux.
import { Provider } from 'react-redux'; import { configureStore } from './store'; ... render( <Provider store={configureStore()}> <App /> </Provider>, document.getElementById('root') );
-
To persist redux state, install:
npm install redux-persist
-
Add persistReducer, storage, and autoMergeLevel2 in store.js
-
Add persistStore and PersistGate in index.js
To connect your app to Redux Dev Tools, configureStore like this inside store.js:
...
export const configureStore = () =>
createStore(
persistedReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
- Always export your component with and without connect functionality (for testing purposes).
- Keep Redux actions and async operations (e.g. fetching data) out of your reducers.
- Reducers must just get the current state and combine it with an action to get the updated state.
- Think about connecting components.
- Avoid connecting your component directly to the store if you want to reuse it with different data. Instead, you should have a parent component which is connected to the store, and passes a correct data to the reusable components.
To manage Redux side-effects. e.g. adding logic to your action calls, etc.
-
To install redux-thunk and required packages:
npm install redux-thunk redux-devtools-extension @babel/runtime
- redux-devtools-extension: to add thunk middleware to our store
- @babel/runtime: to make our async thunks work
-
We also need to install this package (development version of babel):
npm install --save-dev @babel/plugin-transform-runtime
-
Add "plugins" section to your .babelrc file
-
Modify store.js file
In redux a thunk is a function that returns another function which contains the actual logic that we want to perform when it is triggered.
Name | Usage |
---|---|
Component | Display data |
Reducers | Manage state |
Thunks | Side-effect logic |
Reselectors | Abstracting the state's format |
A tool to building more complex logic on top of simpler selectors, and even combine different selectors.
npm install reselect
You can pass as many selectors as you want for the first argument, then use a function to get the result of all of them as parameters.
- getIncompleteTodos is a higher order selector. Has no idea how the data is formatted in Redux Store.
export const getIncompleteTodos = createSelector(
getTodos,
getTodosLoading,
(todos, isLoading) =>
isLoading ? [] : todos.filter((todo) => !todo.isCompleted)
);
npm install styled-components
npm install --save-dev mocha chai
npm install --save-dev @babel/register
- @babel/register: to make test able to run modern babel code
To test our thunks, we use these packages:
npm install --save-dev sinon node-fetch fetch-mock
- sinon: to create a fake function that we can pass in that keeps track of what arguments it was called with. (for dispatch function)