К концу этого блога вы будете знать, как настроить Redux Toolkit и создать приложение To do. Для этого урока я предполагаю, что вы уже знакомы с React.
Почему мне следует использовать инструментарий Redux?
Redux — это библиотека управления состоянием, которая позволяет вам управлять состоянием в любой интерфейсной среде, а Redux Toolkit упрощает написание хороших Redux-приложений и ускоряет разработку, используя наши рекомендуемые передовые методы, предоставляя хорошее поведение по умолчанию, обнаружение ошибок и возможность писать более простой код.
Шаги:
- Выполните указанную ниже команду, удалите ненужные коды и файлы, такие как логотип React, и протестируйте свое приложение.
npx create-react-app React-Redux-Toolkit-TODOAPP cd React-Redux-Toolkit-TODOAPP npm start
2. Установите необходимые пакеты.
npm install @reduxjs/toolkit react-redux react-icons
@reduxjs/toolkit react-redux: библиотека инструментов Redux и Redux.
react-icons: легко включайте популярные значки в свои проекты React с помощью react-icons, который использует импорт ES6, что позволяет вам включать только значки, которые использует ваш проект.
3. Создайте файл с именем src/store.js. Импортируйте API configureStore из Redux Toolkit. Мы начнем с создания пустого магазина Redux и его экспорта.
import { configureStore } from '@reduxjs/toolkit' export default configureStore({ reducer: {} })
4. Предоставьте магазин Redux для реагирования.
Как только хранилище создано, мы можем сделать его доступным для наших компонентов React, поместив React-Redux ‹Provider› вокруг нашего приложения в src/store.js. Импортируйте магазин Redux, который мы только что создали, поместите Provider вокруг вашего «Приложения» и передайте магазин как опору.
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; import store from './store'; import { Provider } from 'react-redux'; ReactDOM.render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode>, document.getElementById('root') ); reportWebVitals();
5. Создайте слайдер Redux
Создайте файл с именем Reducers/todoSlider.js и импортируйте createSlider из Redux Toolkit Api.
Слайсеру требуется строковое имя для идентификации среза, начальное значение состояния и одна или несколько функций сокращения, чтобы определить, как состояние может быть обновлено. Слайсер позволяет нам определить начальное состояние, создать действие и редьюсер в одном месте.
import { createSlice } from '@reduxjs/toolkit' export const toDoSlider = createSlice({ name: 'toDo', initialState: { todoList: [ { id: 1, content: "Hit the gym" }, { id: 2, content: "Meet George"} ] }, reducers: { addToDo: (state, action) => { let newTodoList = { id: Math.random(), content: action.payload.newContent } state.todoList.push(newTodoList); }, deleteToDo: (state, action) => { let { todoList } = state; state.todoList = todoList.filter((item) => item.id !==action.payload.id); }, editTodo: (state, action) => { let { todoList } = state; state.todoList = todoList.map((item) => item.id === action.payload.id ? action.payload : item); } }, }) // Action creators are generated for each case reducer function export const { addToDo, deleteToDo, editTodo } = toDoSlider.actions export default toDoSlider.reducer;
Из приведенного выше кода вы можете наблюдать, что начальное состояние определено, а функции редукторов созданы для выполнения операций добавления, обновления и удаления.
6. Добавьте редукторы Slice в магазин
Затем нам нужно импортировать функцию редуктора из слайса счетчика и добавить ее в наше хранилище внутри src/store.js. Определив поле внутри параметра редуктора, мы указываем хранилищу использовать эту функцию редуктора среза для обработки всех обновлений этого состояния.
import { configureStore } from '@reduxjs/toolkit' import toDoReducer from './Reducers/toDoSlider'; export default configureStore({ reducer: {// allows you create n number of sliders toDo: toDoReducer , })
7. Создание компонентов и импорт в приложение .js
Создайте файл с именем src/Components/AddTodo.js.
import React, { useState } from 'react'; import { useDispatch } from 'react-redux'; import { addToDo } from '../Reducers/toDoSlider'; const AddTodo = () => { const dispatch = useDispatch(); const [ state, setState ] = useState({ content: '', contentError: null }); const handleChange = (e) =>{ setState({...state, [e.target.name]: e.target.value, [`${e.target.name}Error`]: null }); } const add = () =>{ if(content === ''){ setState({...state, contentError: 'You must write something!'}); return; } dispatch(addToDo({newContent: content})); setState({...state, content: ''}); } const { content, contentError } = state; return <div className='form'> <h2>What's your plan for today</h2> <input type='text' value={content} name='content' onChange={handleChange}> </input> <button type='button' className='button' onClick={add}>Add </button> {contentError ? <div className='error'>{contentError}</div>: null} </div>; }; export default AddTodo;
Из приведенного выше кода вы можете увидеть, что хук Redux useDispatch используется для отправки действия addToDo для обновления состояния.
Создайте файл с именем src/Components/ListTodo.js.
import React, { useState } from 'react'; import { AiFillEdit, AiOutlineCloseCircle } from "react-icons/ai"; import { useDispatch, useSelector } from 'react-redux'; import { deleteToDo, editTodo } from '../Reducers/toDoSlider'; const ListTodo = () => { const { todoList } = useSelector((state) => state.toDo); const dispatch = useDispatch(); const [ isEditing, setEditing ] = useState(false); const [ state, setState ] = useState({ id: '', content: '', contentError: null }); const onEditToggle = ( id, content) => { setEditing(true); setState({ ...state, id, content}); } const handleChange = (e) =>{ setState({...state, [e.target.name]: e.target.value, [`${e.target.name}Error`]: null }); } const { content, contentError, id } = state; const edit = () =>{ if(content === ''){ setState({...state, contentError: 'You must write something!'}); return; } dispatch((editTodo({content, id}))); setEditing(false); } return <div> { isEditing ? <div className='form'> <h2>Update your plan for today</h2> <input type='text' value={content} name='content' onChange={handleChange}> </input> <button type='button' className='button' onClick={edit}>Edit </button> {contentError ? <div className='error'>{contentError}</div>: null } </div> : <ul className='todos'> { todoList.map(({id, content})=> { return <li className='grid' key={id}> <span className='content'>{content}</span> <span className='todo-action'> <AiOutlineCloseCircle className="close" onClick={() => dispatch(deleteToDo({id}))} /> <AiFillEdit className="edit" onClick={() =>onEditToggle(id, content)} /> </span> </li> }) } </ul> } </div>; }; export default ListTodo;
В приведенном выше компоненте Redux hook useDispatch используется для отправки действий deleteToDo, editTodo и useSelector для получения состояния от редуктора.
Импорт компонентов в App.js
import './App.css'; import AddTodo from './Components/AddTodo'; import ListTodo from './Components/ListTodo'; function App() { return ( <div className="App"> <AddTodo /> <ListTodo /> </div> ); } export default App;
7.Добавьте стили в app.css
/* variables */ :root{ --primary: #FFC636; --secondary: #0A0B5B; } /* reset */ body,p,a,ul,li{ margin: 0; padding: 0; text-decoration: none; } li{ list-style-type: none; } /* base styles */ body{ background: var(--secondary); overflow-x: hidden; } .button{ background: none; border: 2px solid var(--primary); color: var(--primary); padding: 6px 12px; border-radius: 10px; text-transform: uppercase; box-shadow: 1px 2px 3px rgba(0,0,0,0.6); display: inline-block; font-size: 1em; margin-left: 5px; } .button:hover{ color: #222; background: var(--primary); } input{ background: rgba(255,255,255,0.05); padding: 10px 16px; border-radius: 10px; border: 2px solid #9893D8; color: #f2f2f2; font-size: 1em; } .error{ color: rgb(187, 30, 30); text-align: left; margin-left: 2px; } /* fonts */ body{ color: #f2f2f2; } /* mobile styles */ .App{ margin: 5%; } .form{ text-align: center; } .grid{ display: grid; grid-template-columns: repeat(8, 1fr); gap: 10px; box-sizing: border-box; } .todos{ margin-top: 20px; } .todos li{ margin-top: 10px; background-color: #6767ab; padding: 3%; box-shadow: 1px 2px 3px honeydew; cursor: pointer; } .content{ grid-column: 1/8; } .todo-action{ display: flex; font-size: 1.5em } /* small tablet styles */ @media screen and (min-width: 620px){ input{ width: 300px; } .todos li{ margin: 10px 20%; padding: 2%; } } /* large tablet & laptop styles */ @media screen and (min-width: 960px){ .todos li{ margin: 10px 25%; } } @media screen and (min-width: 1200px){ .todos li{ margin: 10px 33%; padding: 1%; } }
Вывод: