Как работает useParams()

Миссия

Explain how const { id } = useParams() works.

Объяснение

Что делает useParams() )

Он извлекает динамические параметры из URL-адреса и делает их доступными в качестве свойств объекта.
Затем этот объект возвращается из useParams().

Например, если URL-адрес — /todos/123, где 123 — динамический параметр, то вызов useParams() в компоненте, отображаемом маршрутом /todos/:id, вернет объект, подобный { id: "123" }.

Синтаксис деструктурирования const { id } = useParams() используется
для извлечения значения свойства id из объекта,
возвращаемого useParams().
Это сокращенный вариант записи const id = useParams().id.

Итак, переменная id исходит из объекта, возвращаемого useParams().

Синтаксис деструктурирования используется для извлечения значения свойства
id из объекта и присвоения его
переменной с тем же именем.

Упражняться

Посмотрите, как useParams() работает в проекте React.

Деталь.jsx

import React, { useEffect } from "react";
import styled from "styled-components";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate, useParams } from "react-router-dom";
import { getTodoByID } from "../redux/modules/todos.js";

const Detail = () => {
  const dispatch = useDispatch();
  const todo = useSelector((state) => state.todos.todo);
  console.log(todo)

  const { id } = useParams();
  // console.log(id)
  const navigate = useNavigate();

  useEffect(()=>{
    dispatch(getTodoByID(id))
  }, [dispatch,id])

  return (
    <StContainer>
      <StDialog>
        <div>
          <StDialogHeader>
            <div>ID :{todo.id}</div>
            <StButton
              borderColor="#ddd"
              onClick={() => {
                navigate("/");
              }}
            >
              이전으로
            </StButton>
          </StDialogHeader>
          <StTitle>{todo.title}</StTitle>
          <StBody>{todo.body}</StBody>
        </div>
      </StDialog>
    </StContainer>
  );
};

export default Detail;

todos.js

// Action value
const ADD_TODO = "ADD_TODO";
const GET_TODO_BY_ID = "GET_TODO_BY_ID";
const DELETE_TODO = "DELETE_TODO";
const TOGGLE_STATUS_TODO = "TOGGLE_STATUS_TODO";

// Action Creator
// Todo를 추가하는 action creator
export const addTodo = (payload) => {
  return {
    type: ADD_TODO,
    payload,
  };
};

// Todo를 지우는 action creator
export const deleteTodo = (payload) => {
  return {
    type: DELETE_TODO,
    payload,
  };
};

// Todo를 isDone를 변경하는 action creator
export const toggleStatusTodo = (payload) => {
  return {
    type: TOGGLE_STATUS_TODO,
    payload,
  };
};

// 상세 페이지에서 특정 Todo만 조회하는 action creator
export const getTodoByID = (payload) => {
  return {
    type: GET_TODO_BY_ID,
    payload,
  };
};

// initial state
const initialState = {
  todos: [
    {
      id: "1",
      title: "리액트",
      body: "리액트를 배워봅시다",
      isDone: false,
    },
  ],
  todo: {
    id: "0",
    title: "",
    body: "",
    isDone: false,
  },
};

const todos = (state = initialState, action) => {
  
  switch (action.type) {
    case ADD_TODO:
      return {
        ...state,
        todos: [...state.todos, action.payload],
      };

    case DELETE_TODO:
      return {
        ...state,
        todos: state.todos.filter((todo) => {return todo.id !==action.payload})
      } 

    case TOGGLE_STATUS_TODO:
      return {
        ...state,
        todos: state.todos.map((todo) => {
          if (todo.id === action.payload) {
            return {
              ...todo,
              isDone: !todo.isDone,
            };
          } else {
            return todo;
          }
        }),
      };
    
    case GET_TODO_BY_ID:
      return {
        ...state,
        todo: state.todos.find((todo) => {
          return todo.id === action.payload;
        }),
      };
    default:
      return state;
  }
};

export default todos;

Часть, на которой мы должны сосредоточиться, будет здесь.

Router.jsx

<Route path="/" element={<Home />} />
<Route path="/:id" element={<Detail />} />

Деталь.jsx

const { id } = useParams();

useEffect(()=>{
    dispatch(getTodoByID(id))
  }, [dispatch,id])

Теперь мы видим, что компонент Detail отображается для любого маршрута с динамическим параметром в URL-адресе. Таким образом, можно было использовать деструктурирование для присвоения значения свойству id. теперь мы можем легко получить значение свойства «id», просто используя переменную «id».

Как мы видим, мы использовали переменную id, которая является значением параметра url, в качестве параметра создателя действия getTodoByID.

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

И мы отправили эту функцию на редюсер. Есть редюсер, который имеет такое же имя случая, что и тип действия.

todos.js

case GET_TODO_BY_ID:
      return {
        ...state,
        todo: state.todos.find((todo) => {
          return todo.id === action.payload;
        }),
      };

Теперь возвращаемое значение этого редуктора будет сохранено в хранилище.

Как мы видим, этот редюсер изменит значение свойства todo. И данные свойства todo будут найдены из state.todos, который имеет форму массива. Поэтому я использовал метод фильтра, чтобы найти элемент todos, который имеет то же значение идентификатора, что и action.payload (свойство id URL-адреса страницы сведений).

Как мы видим весь код todos.js, начальное состояние state.todo было таким.

const initialState = {
  todo: {
    id: "0",
    title: "",
    body: "",
    isDone: false,
  },
};

Но поскольку мы нашли данные из свойства «todos», которые имеют то же значение id, что и параметр URL страницы сведений, теперь пустая часть заголовка и тела будет заполнена заголовком и телом из найденного элемента «todos».

Таким образом, новая форма свойства todo в редукторе todos будет сохранена в хранилище. И мы можем использовать эти данные для любого компонента в этом проекте.

А вот код, как я использовал эти данные для создания страницы подробностей.

Деталь.jsx

const todo = useSelector((state) => state.todos.todo);

Я принес данные, сохраненные в хранилище, с помощью useSelector.

И данные, которые я принес, были state.todos.todo, и я присвоил это значение новой переменной с именем «todo».

с помощью этой переменной todo я мог бы создать страницу сведений.

<div>
<StDialogHeader>
  <div>ID :{todo.id}</div>
  <StButton
    borderColor="#ddd"
    onClick={() => {
      navigate("/");
    }}
  >
    이전으로
  </StButton>
</StDialogHeader>
<StTitle>{todo.title}</StTitle>
<StBody>{todo.body}</StBody>
</div>

Поскольку todo само по себе тоже было объектом, я мог использовать данные todo, используя точечную нотацию.

Я использовал свойство id, title, body из объекта todo, чтобы показать подробную информацию о каждом todobox.

Что я выучил

  • Хук useParams используется для извлечения «параметров динамического URL» из текущего маршрута. Другими словами, он позволяет вам получить доступ к значениям динамических сегментов в пути URL.
  • Метод find() — это метод массива в JavaScript, который используется для поиска в массиве и возврата «первого элемента», соответствующего заданному условию.