├── .env
├── .gitignore
├── README.md
├── package.json
├── public
├── favicon.ico
├── index.html
├── logo192.png
├── logo512.png
├── manifest.json
└── robots.txt
├── redux-toolkit-crud-hooks-example-redux-store-architecture.png
├── redux-toolkit-crud-hooks-example.png
├── src
├── App.css
├── App.js
├── components
│ ├── AddTutorial.js
│ ├── Tutorial.js
│ └── TutorialsList.js
├── http-common.js
├── index.css
├── index.js
├── logo.svg
├── reportWebVitals.js
├── services
│ └── TutorialService.js
├── setupTests.js
├── slices
│ └── tutorials.js
└── store.js
└── yarn.lock
/.env:
--------------------------------------------------------------------------------
1 | PORT=8081
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Redux-Toolkit CRUD example with React Hooks, Axios & Web API
2 | Build Redux-Toolkit CRUD application with React Hooks and Rest API calls in that:
3 | - Each item has id, title, description, published status.
4 | - We can create, retrieve, update, delete items.
5 | - There is a Search bar for finding items by title.
6 |
7 | 
8 |
9 | Redux Store:
10 |
11 | 
12 |
13 | For instruction, please visit:
14 | > [Redux-Toolkit CRUD example with React Hooks, Axios & Web API](https://www.bezkoder.com/redux-toolkit-crud-react-hooks/)
15 |
16 | More Practice:
17 | > [React Hooks + Redux (without Redux-Toolkit) CRUD example with Axios & Web API](https://www.bezkoder.com/react-hooks-redux-crud/)
18 |
19 | > [React Hooks (without Redux) CRUD example with Axios and Web API](https://www.bezkoder.com/react-hooks-crud-axios-api/)
20 |
21 | > [React Table example: CRUD App with react-table v7](https://www.bezkoder.com/react-table-example-hooks-crud/)
22 |
23 | > [React Pagination using Hooks example](https://www.bezkoder.com/react-pagination-hooks/)
24 |
25 | > [React Hooks File Upload example](https://www.bezkoder.com/react-hooks-file-upload/)
26 |
27 | > [React Hooks: JWT Authentication & Authorization example](https://www.bezkoder.com/react-hooks-jwt-auth/)
28 |
29 | > [React + Redux + Hooks: JWT Authentication & Authorization example](https://www.bezkoder.com/react-hooks-redux-login-registration-example/)
30 |
31 | Fullstack with Node.js Express:
32 | > [React + Node.js Express + MySQL](https://www.bezkoder.com/react-node-express-mysql/)
33 |
34 | > [React + Node.js Express + PostgreSQL](https://www.bezkoder.com/react-node-express-postgresql/)
35 |
36 | > [React + Node.js Express + MongoDB](https://www.bezkoder.com/react-node-express-mongodb-mern-stack/)
37 |
38 | Fullstack with Spring Boot:
39 | > [React + Spring Boot + MySQL](https://www.bezkoder.com/react-spring-boot-crud/)
40 |
41 | > [React + Spring Boot + PostgreSQL](https://www.bezkoder.com/spring-boot-react-postgresql/)
42 |
43 | > [React + Spring Boot + MongoDB](https://www.bezkoder.com/react-spring-boot-mongodb/)
44 |
45 | Fullstack with Django:
46 | > [React.js Hooks + Django Rest Framework](https://www.bezkoder.com/django-react-hooks/)
47 |
48 | Serverless with Firebase:
49 | > [React Firebase Hooks: CRUD App with Realtime Database example](https://www.bezkoder.com/react-firebase-hooks-crud/)
50 |
51 | > [React Hooks Firestore example: CRUD App](https://www.bezkoder.com/react-hooks-firestore/)
52 |
53 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
54 |
55 | ### Set port
56 | .env
57 | ```
58 | PORT=8081
59 | ```
60 |
61 | ## Project setup
62 |
63 | In the project directory, you can run:
64 |
65 | ```
66 | npm install
67 | # or
68 | yarn install
69 | ```
70 |
71 | or
72 |
73 | ### Compiles and hot-reloads for development
74 |
75 | ```
76 | npm start
77 | # or
78 | yarn start
79 | ```
80 |
81 | Open [http://localhost:8081](http://localhost:8081) to view it in the browser.
82 |
83 | The page will reload if you make edits.
84 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-hooks-redux-toolkit-example-crud",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@reduxjs/toolkit": "^1.8.5",
7 | "@testing-library/jest-dom": "^5.14.1",
8 | "@testing-library/react": "^13.0.0",
9 | "@testing-library/user-event": "^13.2.1",
10 | "axios": "^0.27.2",
11 | "bootstrap": "^4.6.2",
12 | "react": "^18.2.0",
13 | "react-dom": "^18.2.0",
14 | "react-redux": "^8.0.1",
15 | "react-router-dom": "^6.4.0",
16 | "react-scripts": "5.0.1",
17 | "web-vitals": "^1.0.1"
18 | },
19 | "scripts": {
20 | "start": "react-scripts start",
21 | "build": "react-scripts build",
22 | "test": "react-scripts test",
23 | "eject": "react-scripts eject"
24 | },
25 | "eslintConfig": {
26 | "extends": [
27 | "react-app",
28 | "react-app/jest"
29 | ]
30 | },
31 | "browserslist": {
32 | "production": [
33 | ">0.2%",
34 | "not dead",
35 | "not op_mini all"
36 | ],
37 | "development": [
38 | "last 1 chrome version",
39 | "last 1 firefox version",
40 | "last 1 safari version"
41 | ]
42 | },
43 | "devDependencies": {}
44 | }
45 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bezkoder/redux-toolkit-example-crud-hooks/0a5fd08d9c02870bab784932ed97e82ee267304d/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | React App
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bezkoder/redux-toolkit-example-crud-hooks/0a5fd08d9c02870bab784932ed97e82ee267304d/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bezkoder/redux-toolkit-example-crud-hooks/0a5fd08d9c02870bab784932ed97e82ee267304d/public/logo512.png
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/redux-toolkit-crud-hooks-example-redux-store-architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bezkoder/redux-toolkit-example-crud-hooks/0a5fd08d9c02870bab784932ed97e82ee267304d/redux-toolkit-crud-hooks-example-redux-store-architecture.png
--------------------------------------------------------------------------------
/redux-toolkit-crud-hooks-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/bezkoder/redux-toolkit-example-crud-hooks/0a5fd08d9c02870bab784932ed97e82ee267304d/redux-toolkit-crud-hooks-example.png
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .list {
2 | text-align: left;
3 | max-width: 750px;
4 | margin: auto;
5 | }
6 |
7 | .submit-form {
8 | max-width: 300px;
9 | margin: auto;
10 | }
11 |
12 | .edit-form {
13 | max-width: 300px;
14 | margin: auto;
15 | }
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { BrowserRouter as Router, Routes, Route, Link } from "react-router-dom";
3 | import "bootstrap/dist/css/bootstrap.min.css";
4 | import "./App.css";
5 |
6 | import AddTutorial from "./components/AddTutorial";
7 | import Tutorial from "./components/Tutorial";
8 | import TutorialsList from "./components/TutorialsList";
9 |
10 | function App() {
11 | return (
12 |
13 |
30 |
31 |
32 |
33 | } />
34 | } />
35 | } />
36 | } />
37 |
38 |
39 |
40 | );
41 | }
42 |
43 | export default App;
44 |
--------------------------------------------------------------------------------
/src/components/AddTutorial.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { useDispatch } from "react-redux";
3 | import { createTutorial } from "../slices/tutorials";
4 |
5 | const AddTutorial = () => {
6 | const initialTutorialState = {
7 | id: null,
8 | title: "",
9 | description: "",
10 | published: false
11 | };
12 | const [tutorial, setTutorial] = useState(initialTutorialState);
13 | const [submitted, setSubmitted] = useState(false);
14 |
15 | const dispatch = useDispatch();
16 |
17 | const handleInputChange = event => {
18 | const { name, value } = event.target;
19 | setTutorial({ ...tutorial, [name]: value });
20 | };
21 |
22 | const saveTutorial = () => {
23 | const { title, description } = tutorial;
24 |
25 | dispatch(createTutorial({ title, description }))
26 | .unwrap()
27 | .then(data => {
28 | console.log(data);
29 | setTutorial({
30 | id: data.id,
31 | title: data.title,
32 | description: data.description,
33 | published: data.published
34 | });
35 | setSubmitted(true);
36 | })
37 | .catch(e => {
38 | console.log(e);
39 | });
40 | };
41 |
42 | const newTutorial = () => {
43 | setTutorial(initialTutorialState);
44 | setSubmitted(false);
45 | };
46 |
47 | return (
48 |
49 | {submitted ? (
50 |
51 |
You submitted successfully!
52 |
55 |
56 | ) : (
57 |
58 |
59 |
60 |
69 |
70 |
71 |
72 |
73 |
82 |
83 |
84 |
87 |
88 | )}
89 |
90 | );
91 | };
92 |
93 | export default AddTutorial;
94 |
--------------------------------------------------------------------------------
/src/components/Tutorial.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { useDispatch } from "react-redux";
3 | import { useParams, useNavigate } from 'react-router-dom';
4 | import { updateTutorial, deleteTutorial } from "../slices/tutorials";
5 | import TutorialDataService from "../services/TutorialService";
6 |
7 | const Tutorial = (props) => {
8 | const { id }= useParams();
9 | let navigate = useNavigate();
10 |
11 | const initialTutorialState = {
12 | id: null,
13 | title: "",
14 | description: "",
15 | published: false
16 | };
17 | const [currentTutorial, setCurrentTutorial] = useState(initialTutorialState);
18 | const [message, setMessage] = useState("");
19 |
20 | const dispatch = useDispatch();
21 |
22 | const getTutorial = id => {
23 | TutorialDataService.get(id)
24 | .then(response => {
25 | setCurrentTutorial(response.data);
26 | })
27 | .catch(e => {
28 | console.log(e);
29 | });
30 | };
31 |
32 | useEffect(() => {
33 | if (id)
34 | getTutorial(id);
35 | }, [id]);
36 |
37 | const handleInputChange = event => {
38 | const { name, value } = event.target;
39 | setCurrentTutorial({ ...currentTutorial, [name]: value });
40 | };
41 |
42 | const updateStatus = status => {
43 | const data = {
44 | id: currentTutorial.id,
45 | title: currentTutorial.title,
46 | description: currentTutorial.description,
47 | published: status
48 | };
49 |
50 | dispatch(updateTutorial({ id: currentTutorial.id, data }))
51 | .unwrap()
52 | .then(response => {
53 | console.log(response);
54 | setCurrentTutorial({ ...currentTutorial, published: status });
55 | setMessage("The status was updated successfully!");
56 | })
57 | .catch(e => {
58 | console.log(e);
59 | });
60 | };
61 |
62 | const updateContent = () => {
63 | dispatch(updateTutorial({ id: currentTutorial.id, data: currentTutorial }))
64 | .unwrap()
65 | .then(response => {
66 | console.log(response);
67 | setMessage("The tutorial was updated successfully!");
68 | })
69 | .catch(e => {
70 | console.log(e);
71 | });
72 | };
73 |
74 | const removeTutorial = () => {
75 | dispatch(deleteTutorial({ id: currentTutorial.id }))
76 | .unwrap()
77 | .then(() => {
78 | navigate("/tutorials");
79 | })
80 | .catch(e => {
81 | console.log(e);
82 | });
83 | };
84 |
85 | return (
86 |
87 | {currentTutorial ? (
88 |
89 |
Tutorial
90 |
121 |
122 | {currentTutorial.published ? (
123 |
129 | ) : (
130 |
136 | )}
137 |
138 |
141 |
142 |
149 |
{message}
150 |
151 | ) : (
152 |
153 |
154 |
Please click on a Tutorial...
155 |
156 | )}
157 |
158 | );
159 | };
160 |
161 | export default Tutorial;
162 |
--------------------------------------------------------------------------------
/src/components/TutorialsList.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useCallback } from "react";
2 | import { useDispatch, useSelector } from "react-redux";
3 | import {
4 | retrieveTutorials,
5 | findTutorialsByTitle,
6 | deleteAllTutorials,
7 | } from "../slices/tutorials";
8 | import { Link } from "react-router-dom";
9 |
10 | const TutorialsList = () => {
11 | const [currentTutorial, setCurrentTutorial] = useState(null);
12 | const [currentIndex, setCurrentIndex] = useState(-1);
13 | const [searchTitle, setSearchTitle] = useState("");
14 |
15 | const tutorials = useSelector(state => state.tutorials);
16 | const dispatch = useDispatch();
17 |
18 | const onChangeSearchTitle = e => {
19 | const searchTitle = e.target.value;
20 | setSearchTitle(searchTitle);
21 | };
22 |
23 | const initFetch = useCallback(() => {
24 | dispatch(retrieveTutorials());
25 | }, [dispatch])
26 |
27 | useEffect(() => {
28 | initFetch()
29 | }, [initFetch])
30 |
31 | const refreshData = () => {
32 | setCurrentTutorial(null);
33 | setCurrentIndex(-1);
34 | };
35 |
36 | const setActiveTutorial = (tutorial, index) => {
37 | setCurrentTutorial(tutorial);
38 | setCurrentIndex(index);
39 | };
40 |
41 | const removeAllTutorials = () => {
42 | dispatch(deleteAllTutorials())
43 | .then(response => {
44 | refreshData();
45 | })
46 | .catch(e => {
47 | console.log(e);
48 | });
49 | };
50 |
51 | const findByTitle = () => {
52 | refreshData();
53 | dispatch(findTutorialsByTitle({ title: searchTitle }));
54 | };
55 |
56 | return (
57 |
58 |
59 |
60 |
67 |
68 |
75 |
76 |
77 |
78 |
79 |
Tutorials List
80 |
81 |
82 | {tutorials &&
83 | tutorials.map((tutorial, index) => (
84 | - setActiveTutorial(tutorial, index)}
89 | key={index}
90 | >
91 | {tutorial.title}
92 |
93 | ))}
94 |
95 |
96 |
102 |
103 |
104 | {currentTutorial ? (
105 |
106 |
Tutorial
107 |
108 | {" "}
111 | {currentTutorial.title}
112 |
113 |
114 | {" "}
117 | {currentTutorial.description}
118 |
119 |
120 | {" "}
123 | {currentTutorial.published ? "Published" : "Pending"}
124 |
125 |
126 |
130 | Edit
131 |
132 |
133 | ) : (
134 |
135 |
136 |
Please click on a Tutorial...
137 |
138 | )}
139 |
140 |
141 | );
142 | };
143 |
144 | export default TutorialsList;
145 |
--------------------------------------------------------------------------------
/src/http-common.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | export default axios.create({
4 | baseURL: "http://localhost:8080/api",
5 | headers: {
6 | "Content-type": "application/json"
7 | }
8 | });
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { createRoot } from "react-dom/client";
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 | import store from './store'
7 | import { Provider } from 'react-redux'
8 |
9 | const container = document.getElementById("root");
10 | const root = createRoot(container);
11 |
12 | root.render(
13 |
14 |
15 |
16 | );
17 |
18 | // If you want to start measuring performance in your app, pass a function
19 | // to log results (for example: reportWebVitals(console.log))
20 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
21 | reportWebVitals();
22 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/src/services/TutorialService.js:
--------------------------------------------------------------------------------
1 | import http from "../http-common";
2 |
3 | const getAll = () => {
4 | return http.get("/tutorials");
5 | };
6 |
7 | const get = id => {
8 | return http.get(`/tutorials/${id}`);
9 | };
10 |
11 | const create = data => {
12 | return http.post("/tutorials", data);
13 | };
14 |
15 | const update = (id, data) => {
16 | return http.put(`/tutorials/${id}`, data);
17 | };
18 |
19 | const remove = id => {
20 | return http.delete(`/tutorials/${id}`);
21 | };
22 |
23 | const removeAll = () => {
24 | return http.delete(`/tutorials`);
25 | };
26 |
27 | const findByTitle = title => {
28 | return http.get(`/tutorials?title=${title}`);
29 | };
30 |
31 | const TutorialService = {
32 | getAll,
33 | get,
34 | create,
35 | update,
36 | remove,
37 | removeAll,
38 | findByTitle
39 | };
40 |
41 | export default TutorialService;
--------------------------------------------------------------------------------
/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/src/slices/tutorials.js:
--------------------------------------------------------------------------------
1 | import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
2 | import TutorialDataService from "../services/TutorialService";
3 |
4 | const initialState = [];
5 |
6 | export const createTutorial = createAsyncThunk(
7 | "tutorials/create",
8 | async ({ title, description }) => {
9 | const res = await TutorialDataService.create({ title, description });
10 | return res.data;
11 | }
12 | );
13 |
14 | export const retrieveTutorials = createAsyncThunk(
15 | "tutorials/retrieve",
16 | async () => {
17 | const res = await TutorialDataService.getAll();
18 | return res.data;
19 | }
20 | );
21 |
22 | export const updateTutorial = createAsyncThunk(
23 | "tutorials/update",
24 | async ({ id, data }) => {
25 | const res = await TutorialDataService.update(id, data);
26 | return res.data;
27 | }
28 | );
29 |
30 | export const deleteTutorial = createAsyncThunk(
31 | "tutorials/delete",
32 | async ({ id }) => {
33 | await TutorialDataService.remove(id);
34 | return { id };
35 | }
36 | );
37 |
38 | export const deleteAllTutorials = createAsyncThunk(
39 | "tutorials/deleteAll",
40 | async () => {
41 | const res = await TutorialDataService.removeAll();
42 | return res.data;
43 | }
44 | );
45 |
46 | export const findTutorialsByTitle = createAsyncThunk(
47 | "tutorials/findByTitle",
48 | async ({ title }) => {
49 | const res = await TutorialDataService.findByTitle(title);
50 | return res.data;
51 | }
52 | );
53 |
54 | const tutorialSlice = createSlice({
55 | name: "tutorial",
56 | initialState,
57 | extraReducers: {
58 | [createTutorial.fulfilled]: (state, action) => {
59 | state.push(action.payload);
60 | },
61 | [retrieveTutorials.fulfilled]: (state, action) => {
62 | return [...action.payload];
63 | },
64 | [updateTutorial.fulfilled]: (state, action) => {
65 | const index = state.findIndex(tutorial => tutorial.id === action.payload.id);
66 | state[index] = {
67 | ...state[index],
68 | ...action.payload,
69 | };
70 | },
71 | [deleteTutorial.fulfilled]: (state, action) => {
72 | let index = state.findIndex(({ id }) => id === action.payload.id);
73 | state.splice(index, 1);
74 | },
75 | [deleteAllTutorials.fulfilled]: (state, action) => {
76 | return [];
77 | },
78 | [findTutorialsByTitle.fulfilled]: (state, action) => {
79 | return [...action.payload];
80 | },
81 | },
82 | });
83 |
84 | const { reducer } = tutorialSlice;
85 | export default reducer;
--------------------------------------------------------------------------------
/src/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from '@reduxjs/toolkit'
2 | import tutorialReducer from './slices/tutorials';
3 |
4 | const reducer = {
5 | tutorials: tutorialReducer
6 | }
7 |
8 | const store = configureStore({
9 | reducer: reducer,
10 | devTools: true,
11 | })
12 |
13 | export default store;
--------------------------------------------------------------------------------