Skip to content
Snippets Groups Projects
Commit 23ec2b05 authored by Björn Modée's avatar Björn Modée Committed by Victor Löfgren
Browse files

Resolve "Add redux"

parent 59a4e4dc
No related branches found
No related tags found
1 merge request!25Resolve "Add redux"
Pipeline #36166 passed
Showing
with 367 additions and 36 deletions
{
"CurrentProjectSetting": null
}
\ No newline at end of file
{
"ExpandedNodes": [
""
],
"PreviewInSolutionExplorer": false
}
\ No newline at end of file
File added
File added
{ {
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",
"parserOptions": { "parserOptions": {
"sourceType": "module", "sourceType": "module",
"project": [ "project": [
"tsconfig.json" "tsconfig.json"
] ]
}, },
"ecmaFeatures": { "ecmaFeatures": {
"jsx": true "jsx": true
}, },
"settings": { "settings": {
"react": { "react": {
"version": "detect" "version": "detect"
}
},
"extends": [
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"prettier/@typescript-eslint",
"plugin:prettier/recommended"
],
"rules": {
"prettier/prettier": ["warn"]
} }
},
"extends": [
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"prettier/@typescript-eslint",
"plugin:prettier/recommended"
],
"rules": {
"prettier/prettier": ["warn"]
} }
}
\ No newline at end of file \ No newline at end of file
This file is a short description of what Redux is,
to learn more about redux, visit https://redux.js.org/
====Install===============================================
To install Redux type the following in the terminal:
npm install redux react-redux
npm install @reduxjs/toolkit
If you have not done so already install axios:
npm install react-axios
npm install axios
Also, a good tool to use is the browser plugin. This allows you to se the state in real time.
It even has a useful playback feature. install it here:
Chrome:
https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd
Firefox:
https://addons.mozilla.org/en-US/firefox/addon/reduxdevtools/
=========================================================
What is Redux?
Redux is a pattern and library for managing and updating
application state, using events called "actions". It serves
as a centralized store for state that needs to be used
across your entire application, with rules ensuring that
the state can only be updated in a predictable fashion.
The center of every Redux application is the store.
A "store" is a container that holds your application's
global state.
A store is a JavaScript object with a few special functions
and abilities that make it different than a plain global object:
- You must never directly modify or change the state that is
kept inside the Redux store
- Instead, the only way to cause an update to the state is to
create a plain action object that describes "something that
happened in the application", and then dispatch the action to
the store to tell it what happened.
- When an action is dispatched, the store runs the root reducer
function, and lets it calculate the new state based on the old
state and the action
Finally, the store notifies subscribers that the state has been
updated so the UI can be updated with the new data.
Redux uses several types of code:
- Actions are plain objects with a type field, and describe
"what happened" in the app
- Reducers are functions that calculate a new state value
based on previous state + an action
- A Redux store runs the root reducer whenever an action
is dispatched
Cite: https://redux.js.org/tutorials/fundamentals/part-1-overview
More useful links on the subject:
https://www.youtube.com/watch?v=CVpUuw9XSjY
\ No newline at end of file
...@@ -1895,6 +1895,17 @@ ...@@ -1895,6 +1895,17 @@
} }
} }
}, },
"@reduxjs/toolkit": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.5.0.tgz",
"integrity": "sha512-E/FUraRx+8guw9Hlg/Ja8jI/hwCrmIKed8Annt9YsZw3BQp+F24t5I5b2OWR6pkEHY4hn1BgP08FrTZFRKsdaQ==",
"requires": {
"immer": "^8.0.0",
"redux": "^4.0.0",
"redux-thunk": "^2.3.0",
"reselect": "^4.0.0"
}
},
"@rollup/plugin-node-resolve": { "@rollup/plugin-node-resolve": {
"version": "7.1.3", "version": "7.1.3",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz",
...@@ -2312,6 +2323,16 @@ ...@@ -2312,6 +2323,16 @@
"integrity": "sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA==", "integrity": "sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA==",
"dev": true "dev": true
}, },
"@types/hoist-non-react-statics": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz",
"integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==",
"dev": true,
"requires": {
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0"
}
},
"@types/html-minifier-terser": { "@types/html-minifier-terser": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz",
...@@ -2414,6 +2435,18 @@ ...@@ -2414,6 +2435,18 @@
"@types/react": "*" "@types/react": "*"
} }
}, },
"@types/react-redux": {
"version": "7.1.16",
"resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz",
"integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==",
"dev": true,
"requires": {
"@types/hoist-non-react-statics": "^3.3.0",
"@types/react": "*",
"hoist-non-react-statics": "^3.3.0",
"redux": "^4.0.0"
}
},
"@types/react-router": { "@types/react-router": {
"version": "5.1.11", "version": "5.1.11",
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.11.tgz", "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.11.tgz",
...@@ -7844,9 +7877,9 @@ ...@@ -7844,9 +7877,9 @@
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==" "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw=="
}, },
"immer": { "immer": {
"version": "7.0.9", "version": "8.0.1",
"resolved": "https://registry.npmjs.org/immer/-/immer-7.0.9.tgz", "resolved": "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz",
"integrity": "sha512-Vs/gxoM4DqNAYR7pugIxi0Xc8XAun/uy7AQu4fLLqaTBHxjOP9pJ266Q9MWA/ly4z6rAFZbvViOtihxUZ7O28A==" "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA=="
}, },
"import-cwd": { "import-cwd": {
"version": "2.1.0", "version": "2.1.0",
...@@ -11033,9 +11066,9 @@ ...@@ -11033,9 +11066,9 @@
} }
}, },
"open": { "open": {
"version": "7.4.0", "version": "7.4.2",
"resolved": "https://registry.npmjs.org/open/-/open-7.4.0.tgz", "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz",
"integrity": "sha512-PGoBCX/lclIWlpS/R2PQuIR4NJoXh6X5AwVzE7WXnWRGvHg7+4TBCgsujUgiPpm0K1y4qvQeWnCWVTpTKZBtvA==", "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==",
"requires": { "requires": {
"is-docker": "^2.0.0", "is-docker": "^2.0.0",
"is-wsl": "^2.1.1" "is-wsl": "^2.1.1"
...@@ -12771,10 +12804,15 @@ ...@@ -12771,10 +12804,15 @@
"whatwg-fetch": "^3.4.1" "whatwg-fetch": "^3.4.1"
} }
}, },
"react-axios": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/react-axios/-/react-axios-2.0.4.tgz",
"integrity": "sha512-QsTq7C/NwsjfrSmFVxPo29BdX6DtLpRF0fZTJv5/R4BanOm+c4639B3Xb4lF83ZfAOX5IW8XG7htz4V+WNF+WA=="
},
"react-dev-utils": { "react-dev-utils": {
"version": "11.0.2", "version": "11.0.3",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.2.tgz", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.3.tgz",
"integrity": "sha512-xG7GlMoYkrgc2M1kDCHKRywXMDbFnjOB+/VzpytQyYBusEzR8NlGTMmUbvN86k94yyKu5XReHB8eZC2JZrNchQ==", "integrity": "sha512-4lEA5gF4OHrcJLMUV1t+4XbNDiJbsAWCH5Z2uqlTqW6dD7Cf5nEASkeXrCI/Mz83sI2o527oBIFKVMXtRf1Vtg==",
"requires": { "requires": {
"@babel/code-frame": "7.10.4", "@babel/code-frame": "7.10.4",
"address": "1.1.2", "address": "1.1.2",
...@@ -12789,7 +12827,7 @@ ...@@ -12789,7 +12827,7 @@
"global-modules": "2.0.0", "global-modules": "2.0.0",
"globby": "11.0.1", "globby": "11.0.1",
"gzip-size": "5.1.1", "gzip-size": "5.1.1",
"immer": "7.0.9", "immer": "8.0.1",
"is-root": "2.1.0", "is-root": "2.1.0",
"loader-utils": "2.0.0", "loader-utils": "2.0.0",
"open": "^7.0.2", "open": "^7.0.2",
...@@ -12902,6 +12940,18 @@ ...@@ -12902,6 +12940,18 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
}, },
"react-redux": {
"version": "7.2.2",
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.2.tgz",
"integrity": "sha512-8+CQ1EvIVFkYL/vu6Olo7JFLWop1qRUeb46sGtIMDCSpgwPQq8fPLpirIB0iTqFe9XYEFPHssdX8/UwN6pAkEA==",
"requires": {
"@babel/runtime": "^7.12.1",
"hoist-non-react-statics": "^3.3.2",
"loose-envify": "^1.4.0",
"prop-types": "^15.7.2",
"react-is": "^16.13.1"
}
},
"react-refresh": { "react-refresh": {
"version": "0.8.3", "version": "0.8.3",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.8.3.tgz",
...@@ -13223,6 +13273,25 @@ ...@@ -13223,6 +13273,25 @@
"strip-indent": "^3.0.0" "strip-indent": "^3.0.0"
} }
}, },
"redux": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz",
"integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==",
"requires": {
"loose-envify": "^1.4.0",
"symbol-observable": "^1.2.0"
}
},
"redux-devtools-extension": {
"version": "2.13.8",
"resolved": "https://registry.npmjs.org/redux-devtools-extension/-/redux-devtools-extension-2.13.8.tgz",
"integrity": "sha512-8qlpooP2QqPtZHQZRhx3x3OP5skEV1py/zUdMY28WNAocbafxdG2tRD1MWE7sp8obGMNYuLWanhhQ7EQvT1FBg=="
},
"redux-thunk": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.3.0.tgz",
"integrity": "sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw=="
},
"regenerate": { "regenerate": {
"version": "1.4.2", "version": "1.4.2",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
...@@ -13449,6 +13518,11 @@ ...@@ -13449,6 +13518,11 @@
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
}, },
"reselect": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.0.0.tgz",
"integrity": "sha512-qUgANli03jjAyGlnbYVAV5vvnOmJnODyABz51RdBN7M4WaVu8mecZWgyQNkG8Yqe3KRGRt0l4K4B3XVEULC4CA=="
},
"resolve": { "resolve": {
"version": "1.18.1", "version": "1.18.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz",
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
"@material-ui/core": "^4.11.3", "@material-ui/core": "^4.11.3",
"@material-ui/icons": "^4.11.2", "@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.57", "@material-ui/lab": "^4.0.0-alpha.57",
"@reduxjs/toolkit": "^1.5.0",
"@testing-library/jest-dom": "^5.11.9", "@testing-library/jest-dom": "^5.11.9",
"@testing-library/react": "^11.2.5", "@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^12.6.3", "@testing-library/user-event": "^12.6.3",
...@@ -16,14 +17,19 @@ ...@@ -16,14 +17,19 @@
"axios": "^0.21.1", "axios": "^0.21.1",
"formik": "^2.2.6", "formik": "^2.2.6",
"react": "^17.0.1", "react": "^17.0.1",
"react-axios": "^2.0.4",
"react-dom": "^17.0.1", "react-dom": "^17.0.1",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "4.0.2", "react-scripts": "4.0.2",
"redux": "^4.0.5",
"redux-devtools-extension": "^2.13.8",
"typescript": "^4.1.3", "typescript": "^4.1.3",
"web-vitals": "^1.1.0", "web-vitals": "^1.1.0",
"yup": "^0.32.9" "yup": "^0.32.9"
}, },
"devDependencies": { "devDependencies": {
"@types/react-redux": "^7.1.16",
"@types/react-router-dom": "^5.1.7", "@types/react-router-dom": "^5.1.7",
"@typescript-eslint/eslint-plugin": "4.2.0", "@typescript-eslint/eslint-plugin": "4.2.0",
"@typescript-eslint/parser": "4.2.0", "@typescript-eslint/parser": "4.2.0",
......
An action is a plain JavaScript object that has a type field.
The actions, the events that occur in the app based on user input,
and trigger updates in the state
You can think of an action as an event that describes something
that happened in the application.
https://redux.js.org/tutorials/fundamentals/part-2-concepts-data-flow
\ No newline at end of file
import Types from "./types.js";
export function axiosPost(path, data, config = undefined,
startCB = undefined, successCB = undefined, errorCB = undefined){
return {
type: Types.AXIOS_POST,
path,
data,
config,
startCB,
successCB,
errorCB
}
}
export function axiosPostSuccess(path, data, previousAction){
return {
type: Types.AXIOS_POST_SUCCESS,
path,
data,
previousAction
}
}
export function axiosPostError(path, data, previousAction){
return {
type: Types.AXIOS_POST_ERROR,
path,
data,
previousAction
}
}
export function axiosGet(path, data, config = undefined, startCB = undefined, successCB = undefined, errorCB = undefined) {
return {
type: Types.AXIOS_GET,
path,
data,
config,
startCB,
successCB,
errorCB
}
}
export function axiosGetSuccess(path, data, previousAction){
return {
type: Types.AXIOS_GET_SUCCESS,
path,
data,
previousAction
}
}
export function axiosGetError(path, data, previousAction){
return {
type: Types.AXIOS_GET_ERROR,
path,
data,
previousAction
}
}
export const login = () => {
return{
type: 'SIGN_IN'
};
};
/*
// Old code that can be used for comparison
export function login(name, email, id, token) {
return {
type: Types.USER_LOGIN,
name,
email,
id,
token
}
}
export function logout() {
return {
type: Types.USER_LOGOUT,
}
}
*/
\ No newline at end of file
export default {
AXIOS_GET: "AXIOS_GET",
AXIOS_GET_SUCCESS: "AXIOS_GET_SUCCESS",
AXIOS_GET_ERROR: "AXIOS_GET_ERROR",
AXIOS_POST: "AXIOS_POST",
AXIOS_POST_SUCCESS: "AXIOS_POST_SUCCESS",
AXIOS_POST_ERROR: "AXIOS_POST_ERROR",
}
import React from 'react' import React from 'react'
import ReactDOM from 'react-dom' import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { compose, createStore } from 'redux'
import App from './App' import App from './App'
import './index.css' import './index.css'
import allReducers from './reducers/allReducers'
import reportWebVitals from './reportWebVitals' import reportWebVitals from './reportWebVitals'
/*
TypeScript does not know the type of the property.
Therefore, you will get the error; Property ‘__REDUX_DEVTOOLS_EXTENSION_COMPOSE__’
does not exist on type ‘Window’. Hence, you need to add the property to the global window as below.
*/
declare global {
interface Window {
__REDUX_DEVTOOLS_EXTENSION__: typeof compose
}
}
// Create an Advanced global store with the name "store"
// const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose // allows Mozilla plugin to view state in a GUI, https://github.com/zalmoxisus/redux-devtools-extension#13-use-redux-devtools-extension-package-from-npm
// const store = createStore(allReducers, composeEnhancers(applyMiddleware()))
// simple store with plugin
const store = createStore(
allReducers,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
// Provider wraps the app component so that it can access store
ReactDOM.render( ReactDOM.render(
<React.StrictMode> <Provider store={store}>
<App /> <React.StrictMode>
</React.StrictMode>, <App />
</React.StrictMode>
</Provider>,
document.getElementById('root') document.getElementById('root')
) )
......
Redux middleware provides a third-party extension point between dispatching an action,
and the moment it reaches the reducer. People use Redux middleware for logging,
crash reporting, talking to an asynchronous API, routing, and more.
https://redux.js.org/tutorials/fundamentals/part-4-store
\ No newline at end of file
A reducer is a function that receives the current state and an action object,
decides how to update the state if necessary, and returns the new state:
(state, action) => newState.
You can think of a reducer as an event listener which handles events based
on the received action (event) type.
https://redux.js.org/tutorials/fundamentals/part-2-concepts-data-flow
\ No newline at end of file
// Combines all the reducers so that we only have to pass "one" reducer to the store in src/index.tsx
import { combineReducers } from 'redux';
import loggedInReducer from './isLoggedIn';
const allReducers = combineReducers({
// name: state
isLoggedIn: loggedInReducer // You can write "loggedInReducer" because its the same as "loggedInReducer: loggedInReducer"
});
export default allReducers;
\ No newline at end of file
const loggedInReducer = (state = false, action) => { // isLoggedIn has an initial state of false
switch (action.type) {
case 'SIGN_IN':
return !state;
default:
return state;
}
}
export default loggedInReducer
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment