@ghost3ds

Как использовать провайдер контекста с отслеживанием состояния для фильтрации элементов?

Всем привет. Пожалуйста, помогите разобраться с провайдером контекста.

Есть компонент Home, который находится в одной папке. Два других компонента Category и Sort находятся в другой папке. Логика фильтрации элементов находится в компоненте Home. Я хочу, чтобы все стэйты хранились в компоненте Home и, когда я выбираю определенную категорию продукта и тип сортировки, компоненты Category и Sort использовали состояния, находящиеся в Home. В свою очередь это позволит мне в компоненте Home в функции fetch прописать условия, согласно которым будут фильтроваться данные.

Из литературы я узнал, что поставщик контекста может поместить объект в контекст, но не может самостоятельно изменять значения объектов в контексте. Для этого нужно создать компонент с отслеживанием состояния, который будет отображать поставщика контекста.

Итак, что я сделал: в компонент Home создал компонент с отслеживанием состояния:

export const CategoryContext = createContext();
      export function CategoryProvider({ children }) {
      const [active, setActive] = useState(0);
      return (
        <CategoryContext.Provider value={{ active, setActive }}>
          <Category />
        </CategoryContext.Provider>
  );
}

Значения value я взял из компонента Category, при этом useState в Category я удалил.

Компонент Category выглядит так:

import React from 'react';
import { useContext } from 'react';
import { useState } from 'react';
import { CategoryProvider, CategoryContext } from '../pages/Home';

function Category() {
  const {active, setActive} = useContext(CategoryProvider);

  const onClickCategory = (index) => {
    setActive(index);
  };

  const pies = ['Все', 'Осетинские', 'Мясные', 'Закрытые', 'Сытные', 'Русские'];

  return (
    <div className="nav__category">
      <ul className="nav__list">
        {pies.map((value, i) => (
          <li key={i} onClick={() => onClickCategory(i)} className={active === i ? 'active' : ''}>
            {value}
          </li>
        ))}
      </ul>
    </div>
  );
}

export default Category;


Компонент Home выглядит так:

import React, { useEffect, useState } from 'react';
import Category from '../components/Category';
import Sort from '../components/Sort';
import PieBlock from '../components/PieBlock';
import Skeleton from '../components/Skeleton';
import { createContext } from 'react';

// Создаем провайдер контекста с отслеживанием состояния

export const CategoryContext = createContext();

export function CategoryProvider({ children }) {
  const [active, setActive] = useState(0);
  return (
    <CategoryContext.Provider value={{ active, setActive }}>
      <Category />
    </CategoryContext.Provider>
  );
}

const Home = () => {
  const [items, setItems] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    fetch('https://636f5291f2ed5cb047daa480.mockapi.io/items')
      .then((res) => res.json())
      .then((arr) => {
        setItems(arr);
        setIsLoading(false);
      });
  }, []);

  return (
    <>
      <nav className="container menu">
        <Category />
        <Sort />
      </nav>
      <h2 className="category__title">Все пироги</h2>
      {/* Карточки */}
      <div className="card__grid">
        {isLoading
          ? [...new Array(6)].map((_, i) => <Skeleton key={i} />)
          : items.map((obj, i) => <PieBlock {...obj} key={i} />)}
      </div>
    </>
  );
};

export default Home;


При этом ничего не рендерится. Вероятно в компоненте Category я как-то неправильно пытаюсь использовать поставщик контекста, либо совсем не понял как применять контекст с отслеживанием состояния. Подскажите, в каком направлении мне копать, тяжело дается понимание контекста, но хочу разобраться. Буду рад любой помощи. Спасибо.

63766ba161c80822853286.jpeg
  • Вопрос задан
  • 76 просмотров
Решения вопроса 1
daniel_pr
@daniel_pr
Вы неправильно используете контекст.
https://reactjs.org/docs/context.html

Вы должны обернуть в провайдер те компоненты, которые будут использовать ваш контекст, то есть
const Context = createContext();

function ContextProvider({ children }) {
  const [active, setActive] = useState(false);
  return <Context.Provider value={{ active, setActive }} >{children}</Context.Provder>
}

function App() {
  return (
    <ContextProvider>
       <MyComponent />
    </ContextProvider>
  )
}

function MyComponent() {
  const { active, setActive } = useContext(Context);
  ...
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы