epam-ai-conductor 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/README.md +46 -0
  2. package/bin/workshop.js +6 -0
  3. package/dist/auth-check.d.ts +1 -0
  4. package/dist/auth-check.js +45 -0
  5. package/dist/auth-check.js.map +1 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +156 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/content/content/module-1/task/module-1_home-task_components.md +257 -0
  10. package/dist/content/content/module-1/task/module-1_home-task_good_practices.md +69 -0
  11. package/dist/content/content/module-1/task/module-1_home-task_task.md +253 -0
  12. package/dist/content/content/module-1/tests/Button.test.tsx +22 -0
  13. package/dist/content/content/module-1/tests/CourseCard.test.tsx +64 -0
  14. package/dist/content/content/module-1/tests/CourseInfo.test.tsx +73 -0
  15. package/dist/content/content/module-1/tests/Courses.test.tsx +87 -0
  16. package/dist/content/content/module-1/tests/Header.test.tsx +23 -0
  17. package/dist/content/content/module-1/tests/Input.test.tsx +36 -0
  18. package/dist/content/content/module-1/tests/helpers.test.ts +13 -0
  19. package/dist/content/content/module-1/theory/module-1_elements-render.md +66 -0
  20. package/dist/content/content/module-1/theory/module-1_hooks_useEffect.md +178 -0
  21. package/dist/content/content/module-1/theory/module-1_hooks_useState.md +131 -0
  22. package/dist/content/content/module-1/theory/module-1_react.md +64 -0
  23. package/dist/content/content/module-1/theory/module-1_spa.md +74 -0
  24. package/dist/content/content/module-2/task/module-2_home-task_components.md +313 -0
  25. package/dist/content/content/module-2/task/module-2_home-task_good_practices.md +35 -0
  26. package/dist/content/content/module-2/task/module-2_home-task_task.md +210 -0
  27. package/dist/content/content/module-2/tests/App.test.tsx +54 -0
  28. package/dist/content/content/module-2/tests/Login.test.tsx +73 -0
  29. package/dist/content/content/module-2/tests/Registration.test.tsx +70 -0
  30. package/dist/content/content/module-2/tests/SearchBar.test.tsx +39 -0
  31. package/dist/content/content/module-2/theory/module-2_custom-hooks.md +201 -0
  32. package/dist/content/content/module-2/theory/module-2_hooks.md +117 -0
  33. package/dist/content/content/module-2/theory/module-2_react-router.md +328 -0
  34. package/dist/content/content/module-3/task/module-3_home-task_components.md +94 -0
  35. package/dist/content/content/module-3/task/module-3_home-task_good_practices.md +26 -0
  36. package/dist/content/content/module-3/task/module-3_home-task_task.md +170 -0
  37. package/dist/content/content/module-3/tests/App.test.tsx +54 -0
  38. package/dist/content/content/module-3/tests/Courses.test.tsx +87 -0
  39. package/dist/content/content/module-3/tests/CreateAuthor.test.tsx +44 -0
  40. package/dist/content/content/module-3/tests/CreateCourse.test.tsx +122 -0
  41. package/dist/content/content/module-3/theory/module-3_redux-hooks.md +194 -0
  42. package/dist/content/content/module-3/theory/module-3_state-actions-reducers.md +445 -0
  43. package/dist/content/content/module-4/task/module-4_home-task_components.md +187 -0
  44. package/dist/content/content/module-4/task/module-4_home-task_task.md +139 -0
  45. package/dist/content/content/module-4/tests/App.test.tsx +54 -0
  46. package/dist/content/content/module-4/tests/Courses.test.tsx +87 -0
  47. package/dist/content/content/module-4/tests/CreateCourse.test.tsx +122 -0
  48. package/dist/content/content/module-4/tests/Login.test.tsx +73 -0
  49. package/dist/content/content/module-4/theory/module-4_async-redux.md +99 -0
  50. package/dist/content/content/module-4/theory/module-4_private-routes.md +55 -0
  51. package/dist/content/content/module-5/task/module-5_home-task_instruction.md +68 -0
  52. package/dist/content/content/module-5/task/module-5_home-task_task.md +154 -0
  53. package/dist/content/content/module-5/tests/App.test.tsx +54 -0
  54. package/dist/content/content/module-5/tests/CourseCard.test.tsx +64 -0
  55. package/dist/content/content/module-5/tests/Courses.test.tsx +87 -0
  56. package/dist/content/content/module-5/tests/Header.test.tsx +23 -0
  57. package/dist/content/content/module-5/theory/module-5_react-testing-library_example.md +379 -0
  58. package/dist/content/content/module-5/theory/module-5_redux-writing-tests.md +246 -0
  59. package/dist/content/module-1/task/module-1_home-task_components.md +257 -0
  60. package/dist/content/module-1/task/module-1_home-task_good_practices.md +69 -0
  61. package/dist/content/module-1/task/module-1_home-task_task.md +253 -0
  62. package/dist/content/module-1/tests/Button.test.tsx +22 -0
  63. package/dist/content/module-1/tests/CourseCard.test.tsx +64 -0
  64. package/dist/content/module-1/tests/CourseInfo.test.tsx +73 -0
  65. package/dist/content/module-1/tests/Courses.test.tsx +87 -0
  66. package/dist/content/module-1/tests/Header.test.tsx +23 -0
  67. package/dist/content/module-1/tests/Input.test.tsx +36 -0
  68. package/dist/content/module-1/tests/helpers.test.ts +13 -0
  69. package/dist/content/module-1/theory/module-1_elements-render.md +66 -0
  70. package/dist/content/module-1/theory/module-1_hooks_useEffect.md +178 -0
  71. package/dist/content/module-1/theory/module-1_hooks_useState.md +131 -0
  72. package/dist/content/module-1/theory/module-1_react.md +64 -0
  73. package/dist/content/module-1/theory/module-1_spa.md +74 -0
  74. package/dist/content/module-2/task/module-2_home-task_components.md +313 -0
  75. package/dist/content/module-2/task/module-2_home-task_good_practices.md +35 -0
  76. package/dist/content/module-2/task/module-2_home-task_task.md +210 -0
  77. package/dist/content/module-2/tests/App.test.tsx +54 -0
  78. package/dist/content/module-2/tests/Login.test.tsx +73 -0
  79. package/dist/content/module-2/tests/Registration.test.tsx +70 -0
  80. package/dist/content/module-2/tests/SearchBar.test.tsx +39 -0
  81. package/dist/content/module-2/theory/module-2_custom-hooks.md +201 -0
  82. package/dist/content/module-2/theory/module-2_hooks.md +117 -0
  83. package/dist/content/module-2/theory/module-2_react-router.md +328 -0
  84. package/dist/content/module-3/task/module-3_home-task_components.md +94 -0
  85. package/dist/content/module-3/task/module-3_home-task_good_practices.md +26 -0
  86. package/dist/content/module-3/task/module-3_home-task_task.md +170 -0
  87. package/dist/content/module-3/tests/App.test.tsx +54 -0
  88. package/dist/content/module-3/tests/Courses.test.tsx +87 -0
  89. package/dist/content/module-3/tests/CreateAuthor.test.tsx +44 -0
  90. package/dist/content/module-3/tests/CreateCourse.test.tsx +122 -0
  91. package/dist/content/module-3/theory/module-3_redux-hooks.md +194 -0
  92. package/dist/content/module-3/theory/module-3_state-actions-reducers.md +445 -0
  93. package/dist/content/module-4/task/module-4_home-task_components.md +187 -0
  94. package/dist/content/module-4/task/module-4_home-task_task.md +139 -0
  95. package/dist/content/module-4/tests/App.test.tsx +54 -0
  96. package/dist/content/module-4/tests/Courses.test.tsx +87 -0
  97. package/dist/content/module-4/tests/CreateCourse.test.tsx +122 -0
  98. package/dist/content/module-4/tests/Login.test.tsx +73 -0
  99. package/dist/content/module-4/theory/module-4_async-redux.md +99 -0
  100. package/dist/content/module-4/theory/module-4_private-routes.md +55 -0
  101. package/dist/content/module-5/task/module-5_home-task_instruction.md +68 -0
  102. package/dist/content/module-5/task/module-5_home-task_task.md +154 -0
  103. package/dist/content/module-5/tests/App.test.tsx +54 -0
  104. package/dist/content/module-5/tests/CourseCard.test.tsx +64 -0
  105. package/dist/content/module-5/tests/Courses.test.tsx +87 -0
  106. package/dist/content/module-5/tests/Header.test.tsx +23 -0
  107. package/dist/content/module-5/theory/module-5_react-testing-library_example.md +379 -0
  108. package/dist/content/module-5/theory/module-5_redux-writing-tests.md +246 -0
  109. package/dist/content-loader.d.ts +7 -0
  110. package/dist/content-loader.js +26 -0
  111. package/dist/content-loader.js.map +1 -0
  112. package/dist/context-builder.d.ts +2 -0
  113. package/dist/context-builder.js +116 -0
  114. package/dist/context-builder.js.map +1 -0
  115. package/package.json +40 -0
@@ -0,0 +1,87 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, screen } from "@testing-library/react";
3
+ import { Courses } from "../components/Courses/Courses";
4
+
5
+ describe('Courses component', () => {
6
+ const mockedCoursesList = [
7
+ {
8
+ id: "1",
9
+ title: "Course 1",
10
+ description: "Course 1 description",
11
+ creationDate: "2022-01-01",
12
+ duration: 60,
13
+ authors: [
14
+ "27cc3006-e93a-4748-8ca8-73d06aa93b6d",
15
+ "f762978b-61eb-4096-812b-ebde22838167",
16
+ ],
17
+ },
18
+ {
19
+ id: "2",
20
+ title: "Course 2",
21
+ description: "Course 2 description",
22
+ creationDate: "2022-02-01",
23
+ duration: 90,
24
+ authors: ["df32994e-b23d-497c-9e4d-84e4dc02882f"],
25
+ },
26
+ ];
27
+ const onAddClick = jest.fn();
28
+
29
+ test("Should render list of courses", () => {
30
+ render(<Courses courseList={mockedCoursesList} onAddClick={onAddClick} setSelectedCourseId={(id) => {}}/>);
31
+
32
+ const courseElements = screen.getAllByTestId("courseCard");
33
+
34
+ expect(courseElements[0]).toBeInTheDocument();
35
+ expect(courseElements).toHaveLength(2);
36
+ });
37
+
38
+ test("Should render 'Add new course' button", () => {
39
+ render(<Courses courseList={mockedCoursesList} onAddClick={onAddClick} setSelectedCourseId={(id) => {}}/>);
40
+
41
+ const button = screen.getByText(/Add new course/);
42
+
43
+ expect(button).toBeInTheDocument();
44
+ });
45
+
46
+ test("Should render EmptyCourseList component if no courses", () => {
47
+ const mockedEmptyCoursesList: [] = [];
48
+ render(<Courses courseList={mockedEmptyCoursesList} onAddClick={onAddClick} setSelectedCourseId={(id) => {}}/>);
49
+
50
+ const emptyContainerElement = screen.getByTestId("emptyContainer");
51
+ const addButtonElement = screen.getByTestId("addCourse");
52
+
53
+ expect(emptyContainerElement).toBeInTheDocument();
54
+ expect(addButtonElement).toBeInTheDocument();
55
+ });
56
+ })
57
+
58
+ describe('EmptyCourseList', () => {
59
+ const mockedEmptyCoursesList: [] = [];
60
+ const onAddClick = jest.fn();
61
+
62
+ test("Should render title", () => {
63
+ render(<Courses courseList={mockedEmptyCoursesList} onAddClick={onAddClick} setSelectedCourseId={(id) => {}}/>);
64
+
65
+ const title = screen.getByText(/Your List Is Empty/);
66
+
67
+ expect(title).toBeInTheDocument();
68
+ });
69
+
70
+ test("Should render subtitle", () => {
71
+ render(<Courses courseList={mockedEmptyCoursesList} onAddClick={onAddClick} setSelectedCourseId={(id) => {}}/>);
72
+
73
+ const subTitle = screen.getByText(/Please use/);
74
+
75
+ expect(subTitle).toBeInTheDocument();
76
+ });
77
+
78
+ test("Should render button", () => {
79
+ render(<Courses courseList={mockedEmptyCoursesList} onAddClick={onAddClick} setSelectedCourseId={(id) => {}}/>);
80
+
81
+ const button = screen.getByText('ADD NEW COURSE');
82
+
83
+ expect(button).toBeInTheDocument();
84
+ });
85
+ })
86
+
87
+
@@ -0,0 +1,44 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, fireEvent, screen } from "@testing-library/react";
3
+ import { CreateAuthor } from "../components/CreateCourse/components/CreateAuthor/CreateAuthor";
4
+
5
+ describe("CreateAuthor", () => {
6
+ it("should call onCreateAuthor when create button is clicked with valid name", () => {
7
+ const onCreateAuthorMock = jest.fn();
8
+ render(<CreateAuthor onCreateAuthor={onCreateAuthorMock} />);
9
+
10
+ const nameInput = screen.getByTestId(
11
+ "createAuthorInput"
12
+ ) as HTMLInputElement;
13
+ const createButton = screen.getByTestId("createAuthorButton");
14
+
15
+ // Enter a valid name in the input field
16
+ fireEvent.change(nameInput, { target: { value: "John" } });
17
+
18
+ // Click the create button
19
+ fireEvent.click(createButton);
20
+
21
+ // Assert that onCreateAuthor is called with the correct data
22
+ expect(onCreateAuthorMock).toHaveBeenCalledWith({
23
+ name: "John",
24
+ id: expect.any(String),
25
+ });
26
+
27
+ // Assert that the input field is cleared
28
+ expect(nameInput.value).toBe("");
29
+ });
30
+
31
+ it("should not call onCreateAuthor when create button is clicked with an empty name", () => {
32
+ const onCreateAuthorMock = jest.fn();
33
+ render(<CreateAuthor onCreateAuthor={onCreateAuthorMock} />);
34
+
35
+ const createButton = screen.getByTestId("createAuthorButton");
36
+
37
+ // Click the create button without entering a name
38
+
39
+ fireEvent.click(createButton);
40
+
41
+ // Assert that onCreateAuthor is not called
42
+ expect(onCreateAuthorMock).not.toHaveBeenCalled();
43
+ });
44
+ });
@@ -0,0 +1,122 @@
1
+ import "@testing-library/jest-dom";
2
+ import { render, fireEvent, screen } from "@testing-library/react";
3
+ import { CreateCourse } from "../components/CreateCourse/CreateCourse";
4
+
5
+ describe("CreateCourse", () => {
6
+ const mockAuthors = [
7
+ { id: "1", name: "Author 1" },
8
+ { id: "2", name: "Author 2" },
9
+ ];
10
+
11
+ const mockCreateCourse = jest.fn();
12
+ const mockCreateAuthor = jest.fn();
13
+
14
+ beforeEach(() => {
15
+ mockCreateCourse.mockClear();
16
+ mockCreateAuthor.mockClear();
17
+ });
18
+
19
+ it("should create a new course with the entered data", () => {
20
+ render(
21
+ <CreateCourse
22
+ authorsList={mockAuthors}
23
+ createCourse={mockCreateCourse}
24
+ createAuthor={mockCreateAuthor}
25
+ />
26
+ );
27
+
28
+ const titleInput = screen.getByTestId("titleInput");
29
+ const durationInput = screen.getByTestId("durationInput");
30
+ const descriptionTextArea = screen.getByTestId("descriptionTextArea");
31
+ const createCourseButton = screen.getByTestId("createCourseButton");
32
+
33
+ // Enter the course title
34
+ fireEvent.change(titleInput, { target: { value: "Course Title" } });
35
+ fireEvent.change(durationInput, { target: { value: "20" } });
36
+
37
+ // Enter the course description
38
+ fireEvent.change(descriptionTextArea, {
39
+ target: { value: "Course Description" },
40
+ });
41
+
42
+ // Click the create course button
43
+ fireEvent.click(createCourseButton);
44
+
45
+ // Assert that createCourse is called with the correct data
46
+ expect(mockCreateCourse).toHaveBeenCalledWith({
47
+ id: expect.any(String),
48
+ title: "Course Title",
49
+ description: "Course Description",
50
+ creationDate: "",
51
+ duration: 20,
52
+ authors: [],
53
+ });
54
+ });
55
+
56
+ it("should not create a new course with the empty data", () => {
57
+ render(
58
+ <CreateCourse
59
+ authorsList={mockAuthors}
60
+ createCourse={mockCreateCourse}
61
+ createAuthor={mockCreateAuthor}
62
+ />
63
+ );
64
+
65
+ const createCourseButton = screen.getByTestId("createCourseButton");
66
+
67
+ // Click the create course button
68
+ fireEvent.click(createCourseButton);
69
+
70
+ // Assert that createCourse is called with the correct data
71
+ expect(mockCreateCourse).not.toHaveBeenCalled();
72
+ });
73
+
74
+ it("should add an author to the course when CreateAuthor component creates a new author", () => {
75
+ render(
76
+ <CreateCourse
77
+ authorsList={mockAuthors}
78
+ createCourse={mockCreateCourse}
79
+ createAuthor={mockCreateAuthor}
80
+ />
81
+ );
82
+
83
+ const createAuthorButton = screen.getByTestId("createAuthorButton");
84
+ const nameInput = screen.getByTestId(
85
+ "createAuthorInput"
86
+ ) as HTMLInputElement;
87
+
88
+ fireEvent.change(nameInput, { target: { value: "John" } });
89
+
90
+ fireEvent.click(createAuthorButton);
91
+
92
+ expect(mockCreateAuthor).toHaveBeenCalled();
93
+ });
94
+
95
+ it("should display the course authors in the course", () => {
96
+ const mockCourseAuthors = ["1", "2"];
97
+ render(
98
+ <CreateCourse
99
+ authorsList={mockAuthors}
100
+ createCourse={mockCreateCourse}
101
+ createAuthor={mockCreateAuthor}
102
+ />
103
+ );
104
+
105
+ const courseAuthorItems = screen.getAllByTestId("authorItem");
106
+ expect(courseAuthorItems.length).toBe(mockCourseAuthors.length);
107
+ });
108
+ it("should display the empty authors list message when there are no authors", () => {
109
+ render(
110
+ <CreateCourse
111
+ authorsList={[]}
112
+ createCourse={mockCreateCourse}
113
+ createAuthor={mockCreateAuthor}
114
+ />
115
+ );
116
+ const emptyText = screen.getByTestId("emptyText");
117
+
118
+ // Assert that the empty text is displayed
119
+ expect(emptyText).toBeInTheDocument();
120
+ expect(emptyText.textContent).toBe("Authors list is empty");
121
+ });
122
+ });
@@ -0,0 +1,194 @@
1
+ ---
2
+ sidebar_position: 3
3
+ sidebar_label: 'Redux Hooks'
4
+ title: 'Redux Hooks'
5
+ ---
6
+
7
+ As a React, Redux also has hooks.
8
+ In this topic, we will look at the hooks that are used more often and that will be needed to do your homework.
9
+
10
+ ## useSelector()
11
+
12
+ ```js
13
+ const result: any = useSelector(selector: Function, equalityFn?: Function);
14
+ ```
15
+
16
+ Allows you to extract data from the Redux store state, using a selector function.
17
+
18
+ :::info
19
+ The selector function should be [pure](https://en.wikipedia.org/wiki/Pure_function) as it might be executed multiple times and at arbitrary moments. A pure function ensures consistent output and no side effects, maintaining the stability of the application.
20
+ :::
21
+
22
+ The *selector* is called with the entire Redux store state as its sole argument. The selector runs whenever the function component renders. However, if its reference has not changed since the previous render, the hook returns a cached result without re-running the selector.
23
+
24
+ `useSelector()` subscribes to the Redux store and executes your selector whenever an action is dispatched.
25
+
26
+ Some specifics of `useSelector` work:
27
+
28
+ &#11088; The selector can return any value as a result. The return value of the selector will be used as the return value of the `useSelector()` hook.
29
+
30
+ &#11088; When an action is dispatched, `useSelector()` performs a reference comparison between the previous selector result value and the current result value. If the values are different, the component is forced to re-render. However, if the values are the same, the component does not re-render.
31
+
32
+ &#11088; `useSelector()` uses strict `===` reference equality checks by default.
33
+
34
+ &#11088; You can use `useSelector()` multiple times within a single function component. Each invocation of `useSelector()` creates a separate subscription to the Redux store.
35
+
36
+ ### `useSelector` Example
37
+
38
+ Basic usage:
39
+
40
+ ```jsx
41
+ import { useSelector } from 'react-redux';
42
+
43
+ export const CounterComponent = () => {
44
+ const counter = useSelector((state) => state.counter);
45
+
46
+ return <div>{counter}</div>
47
+ }
48
+ ```
49
+ Using props via closure to determine what to extract:
50
+ ```jsx
51
+ import { useSelector } from 'react-redux';
52
+
53
+ export const TodoListItem = (props) => {
54
+ const todo = useSelector((state) => state.todos[props.id]);
55
+
56
+ return <div>{todo.text}</div>
57
+ }
58
+ ```
59
+
60
+ :::tip
61
+ It's a good practice to create a separate callback function and pass it to `useSelector()` to improve code readability and maintainability.
62
+ ```jsx
63
+ // selectors.js
64
+ export const getCounter = state => state.counter;
65
+
66
+ // CounterComponent.jsx
67
+ import React from 'react'
68
+ import { useSelector } from 'react-redux'
69
+
70
+ import { getCounter } from './selectors';
71
+
72
+ export const CounterComponent = () => {
73
+ const counter = useSelector(getCounter) //you don't need to call callback
74
+ return <div>{counter}</div>
75
+ }
76
+ ```
77
+ :::
78
+
79
+ ## useDispatch()
80
+
81
+ ```js
82
+ const dispatch = useDispatch()
83
+ ```
84
+
85
+ This hook provides a reference to the `dispatch` function from the Redux store, allowing you to dispatch actions when needed.
86
+
87
+ In the previous topic, you learned that updating the store requires the use of `actions`. Now, let's see how we can achieve this using `dispatch`.
88
+
89
+ ### `useDispatch` Example
90
+
91
+ ```jsx
92
+ import React from 'react';
93
+ import { useDispatch } from 'react-redux';
94
+
95
+ export const CounterComponent = ({ value }) => {
96
+ const dispatch = useDispatch(); // create an instance
97
+
98
+ return (
99
+ <div>
100
+ <span>{value}</span>
101
+ <button onClick={() => dispatch({ type: 'INCREMENT_COUNTER' })}>
102
+ Increment counter
103
+ </button>
104
+ </div>
105
+ )
106
+ }
107
+ ```
108
+ Upon clicking the button, we call `dispatch` with the action 'INCREMENT_COUNTER'.
109
+ This action triggers the appropriate condition in the reducer, which then updates the store state accordingly.
110
+
111
+ Let's make some modification, to make our call more readable
112
+
113
+ 1. Create a separate file for actions
114
+
115
+ ```js
116
+ // actions.js
117
+
118
+ export const INCREMENT_COUNTER = 'INCREMENT_COUNTER';
119
+
120
+ export const incrementCounerAction = () => ({type: INCREMENT_COUNTER});
121
+ ```
122
+
123
+ 2. Use `incrementCouner` in our `CounterComponent`
124
+ ```jsx
125
+ // CounterComponent.jsx
126
+
127
+ import React from 'react';
128
+ import { useDispatch } from 'react-redux';
129
+
130
+ import { incrementCounerAction } from './actions';
131
+
132
+ export const CounterComponent = ({ value }) => {
133
+ const dispatch = useDispatch() // create an instance
134
+
135
+ return (
136
+ <div>
137
+ <span>{value}</span>
138
+ <button onClick={() => dispatch(incrementCounerAction())}>
139
+ Increment counter
140
+ </button>
141
+ </div>
142
+ )
143
+ }
144
+ ```
145
+
146
+ Let's not stop and add usage of `useSelector` &#128512
147
+
148
+ ```jsx
149
+ // CounterComponent.jsx
150
+
151
+ import React from 'react';
152
+ import { useDispatch, useSelector } from 'react-redux';
153
+
154
+ import {incrementCounerAction} from './actions';
155
+
156
+ export const CounterComponent = () => { // remove the prop, we don't need it here
157
+ const value = useSelector(state => state.counter); // now we take value from the store
158
+ const dispatch = useDispatch();
159
+
160
+ return (
161
+ <div>
162
+ <span>{value}</span>
163
+ <button onClick={() => dispatch(incrementCounerAction())}>
164
+ Increment counter
165
+ </button>
166
+ </div>
167
+ )
168
+ }
169
+ ```
170
+
171
+ As a result after every button click:
172
+ 1. `dispatch` will be called with action `{type: INCREMENT_COUNTER}`.
173
+ 2. The reducer will update the state with the new value of `counter`.
174
+ 3. `useSelector` will return new `counter` value.
175
+ 4. After the store is updated, the component will be re-rendered, and the new counter value will be displayed on the page.
176
+
177
+ :::tip
178
+ If you need to pass the `payload` to the action, you can do it like this:
179
+ ```js
180
+ export const incrementCounerAction = (payload) => ({type: INCREMENT_COUNTER, payload});
181
+ ```
182
+ :::
183
+
184
+ ## Materials
185
+ 1. [React Redux. Hooks (Documentation)](https://react-redux.js.org/api/hooks)
186
+
187
+
188
+
189
+
190
+
191
+
192
+
193
+
194
+