👆Привет всем! В этом руководстве мы создадим простое приложение со списком задач с помощью React и хуков через интерфейс Context API Material UI и, наконец, интеграцию с Firebase 🔥

Часть 1: Установки и конфигурации

Откройте терминал / cmd и введите:

$ sudo npm install -g create-react-app
$ create-react-app todo-list
$ cd todo-list

Добавить интерфейс материала

$ npm i --save @material-ui/core
$ npm install @material-ui/icons

Перейдите в общую папку, откройте файл index.html и введите

<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" />

Добавить генератор UUID

$ npm i --save uuid

Часть 2: Контекстный API

В этой части статьи мы покажем, как использовать и реализовывать контекстный API и редукторы.

Итак, давайте начнем с создания двух папок:

  1. контексты
  2. редукторы

Давайте создадим файл TaskContext.js в папке контекста.

Контекст предоставляет способ передавать данные через дерево компонентов без необходимости передавать реквизиты вручную на каждом уровне.

  1. Создайте функцию компонента стрелки с помощью props:
export const TaskContext = createContext();
const TaskContextProvider = (props) => {
  ...
}
export default TaskContextProvider;

Затем нам нужно вернуть нашего провайдера с элементами диспетчера и задач, наконец, нам нужно реализовать «отсортированный массив», который возвращает отсортированные задачи по isCheked или Not.

return (
  <TaskContext.Provider value={{ tasks,sortedTasks, dispatch }}>      {props.children}
   </TaskContext.Provider>)

Результат:

2. В папке reducer создайте новый файл reducer под названием TaskReducer.js.

Итак, нам нужен метод 3 действий для работы с нашим массивом задач: первое действие необходимо для добавления новой задачи, второе - для проверки задачи, а третье удалит задачу.

Давайте создадим перечисление для этих статических действий

export const Action = {
  ADD_TASK: "add-task",
  CHECK_TASK: "check-task",
  REMOVE_TASK: "remove-task"
}

Давайте создадим редуктор с корпусом переключателя, чтобы заменить тип действия:

Когда добавление задачи выбрано, правильным способом будет выдвинуть новую задачу.

case Action.ADD_TASK: {
  return [...state, action.task]
}

Когда выбран отмеченный тип, нам нужно изменить конкретную задачу в массиве по значению идентификатора задачи.

case Action.CHECK_TASK:{
   let taskIndex = state.findIndex(t => t.id === action.task.id);
   state[taskIndex].isChecked = action.task.isChecked
   return state.filter(task => task.id !== action.id);
}

И удалить задачу будет

case Action.REMOVE_TASK: {
  return state.filter(task => task.id !== action.id)
}

Результат:

Часть 3: Компонент, хуки и UI материала

В этой части статьи мы узнаем, как создать компонент стрелочной функции для каждого события задачи.

Давайте создадим папку components в папке src и создадим 4 компонента:

  1. NavbarComponent.js - src / components / NavbarComponent.js
  2. AddTaskComponent.js - src / components / TodoListComponent.js.
  3. TasksListComponent.js - src / components / tasks / AddTaskComponent.js.
  4. TodoListComponent.js - src / component / tasks / TaskListComponent.js

Примечание: я решил создать еще одну папку в компонентах, называемых задачами.

  1. Откройте NavbarComponent.js, давайте создадим новый компонент и используем контекст
const NavbarComponent = () => {
  const {tasks} = useContext(TaskContext)
}
export default NavbarComponent;

Теперь давайте сделаем навигационную панель, используя материальный интерфейс.

return (
        <AppBar position="static">
            <Toolbar variant="dense" 
                style={{ justifyContent: "center" }} >
                <Typography 
                    variant="h6" 
                    color="inherit">
                    React Todo List ({tasks.length})
                </Typography>
            </Toolbar>
        </AppBar>
    );

Результат:

Https://gist.github.com/shai-benshimol/6a0872107dc9467a3859a9832b60a95c

2. Давайте создадим простой компонент для добавления новой задачи.

3. Давайте создадим новую функцию компонента - TasksListComponent и реализуем useStyles для фонового списка.

const useStyles = makeStyles((theme) => ({
    root: {
        width: '100%',
        backgroundColor: theme.palette.background.transparent,
    },
    marked: {
        textDecoration: 'line-through'
    }
}));

Затем нам нужно использовать контекст задачи для возврата данных из редуктора.

const {
        sortedTasks,
        dispatch,
    } = useContext(TaskContext)

Затем верните jsx, используя материальный интерфейс.

return (
        <List className={classes.root}>
            {sortedTasks.map((task) => {
                return (
                    <ListItem key={task.id}
                        role={undefined}
                        dense
                        button
                        onClick={() => {
                            onChecked(task.id, !task.isChecked)
                        }
                        }>
                        <IconButton color="primary">
                            {
                                !task.isChecked ? (<CropFreeIcon />) : (<LibraryAddCheckIcon />)
                            }
                        </IconButton>
                        <ListItemText primary={task.description}
                            className={task.isChecked ? classes.marked : ''} />
                        <ListItemSecondaryAction>
                            <IconButton
                                edge="end"
                                aria-label="comments"
                                onClick={() => {
                                    dispatch({
                                        type: Action.REMOVE_TASK,
                                        id: task.id
                                    })
                                }}>
                                <DeleteOutlineIcon />
                            </IconButton>
                        </ListItemSecondaryAction>
                    </ListItem>
                );
            })}
        </List>

Результат:

4. Откройте созданный ранее TodoListComponent.js и создайте новый компонент для этого состояния.

В TodoListComponent мы хотим объединить 2 компонента, AddTask и TasksList, в столбец.

Давайте соберем все вместе в App.js… Итак, откройте файл App.js и замените его на

И это все

$ npm run start

Часть 4: Firebase

Я уже создал руководство по интеграции firebase



Теперь давайте создадим новую папку для firebase с двумя подпапками: firebase.config.js и Firebase.js.

В firebase.config.js просто добавьте свои значения из консоли firebase, как:

import firebase from 'firebase';const firebaseConfig = {
  apiKey: "<--->",
  authDomain: "<--->",
  databaseURL: "<--->",
  projectId: "<--->",
  storageBucket: "<--->",
  messagingSenderId: ""<--->",
  appId: "<--->",
  measurementId: "<--->"
};firebase.initializeApp(firebaseConfig)export const db = firebase.firestore()

Откройте «Firebase.js» и добавьте 4 функции.

  1. addTaskReques
  2. getTasksRequest
  3. checkTaskRequest
  4. removeTaskRequest

Добавить запрос задачи:

export const addTaskRequest = async (task) => {
    return await db.collection(collection)
        .add(task)
}

Получить запрос задач

export const getTasksRequest = async () => {
    return await db.collection(collection).get().then(res => {
        let tasks = [];
res.docs.map(task => {
            let data = task.data();
tasks.push({
                id: data.id,
                isChecked: data.isChecked,
                description: data.description,
                created: data.created
            })
        })
        return  tasks;
    })
}

Проверить запрос задачи

export const checkTaskRequest = (id, isChecked) => {
    return db.collection(collection)
        .doc(id)
        .set({
            isChecked: isChecked
        })
}

Удалить запрос задачи

export const removeTaskRequest = (id) => {
    return await db.collection(collection)
            .db.collection(collection)
            .doc(id)
            .delete()
}

Конечный результат

Часть 5: useEffect

Обработчик эффекта, useEffect, добавляет возможность выполнять побочные эффекты из функционального компонента. Он служит той же цели, что и componentDidUpdate и componentWillUnmount в классах React, но объединен в единый API. (Мы покажем примеры сравнения useEffect с этими методами в Использование обработчика эффектов.)

Теперь давайте внесем некоторые изменения в «TaskComponent.js», создадим массив useState для setTasks из хранилища firebase, а затем создадим хук useEffect следующим образом:

const [sortedTasks,setTasks] = useState([]);
const count = sortedTasks.length;
    useEffect(()=>{
        getTasksRequest().then(res=>{
            setTasks(res.sort((t, f) =>  (f.isChecked === t.isChecked)? 0 : f.isChecked? -1 : 1))
            dispatch({
                type:Action.GET_ALL_TASKS,
                res
            })
        })
    },[])

Конечный результат

Вывод

Мы узнали, как обрабатывать локальное состояние с помощью Context API и хуков, создавать пользовательский интерфейс с пользовательским интерфейсом материала и хранить данные в облаке firebase.

My ko-fi