Как передать состояние из дочернего в основной?

Я только недавно начал изучать реакт, поэтому тухлыми помидорами в меня прошу не кидаться, а просто дать дельную подсказку. Делаю страницу Блога. У меня есть основной Blog.tsx, где находятся все компоненты. И есть компонент Filter , в котором находятся кнопки по переключению тематики(которые я отмэпил и отфлитровал исходя из тематик всех, которые есть в массиве объектов) Так же в Filter прописана логика, по которой фильтруются посты блога.

Мне нужно, filtred вот отсюда (находится в компоненте Filter)

 const [filtred, setFiltred] = useState(posts)

передать в Blog.tsx, чтобы пробежаться мэпом уже по filtred, а не по изначальному posts.

Как это можно реализовать?

Куски кода Blog.tsx

import React from "react";
import './Blog.scss'
import {Post} from "./components/Post/Post";
import {Best} from "./components/Best/Best";
import {Filter} from "./components/Filter/Filter";

interface Props {

}

export const Blog = () => {


    return (
        <div className='background__blog'>
            <div className='container'>
                <div className='blog__title'>Блог</div>
                <div className='blog__content'>
                    <div className='content__posts'>{filtred.map((post) => <Post post={post} key={post.id}/>)}</div>
                    <div className='content__panel'>
                        <div className='panel__filter'>
                            <div className='filter__text'>Фильтр по тематике</div>
                            <Filter />
                        </div>
                        <div className='panel__best'><Best/></div>
                    </div>
                </div>
            </div>
        </div>
    );
};

Filter.tsx

import React, {useState} from 'react';
import {posts} from "../../../../data/Posts";

interface Props {
}

export const Filter = () => {

    const [filtred, setFiltred] = useState(posts)

    function ArrFilter(Themes: string) {
        if (Themes === 'all') {
            setFiltred(posts)
        } else {
            let newArr = [...posts].filter(post => post.Themes === Themes)
            setFiltred(newArr)
        }
    }


    const FillArr: {[Themes: string]: number} = {};
    const fill = posts.filter(({Themes}) => (!FillArr[Themes] && (FillArr[Themes] = 1)));

    return (
        <div className='filter__btn'>
            <button onClick={() => ArrFilter('all')}>Все</button>
            <>{fill.map((FillArr) =><button onClick={() => ArrFilter(FillArr.Themes)}>{FillArr.Themes}</button>)}</>
        </div>
    );
};

{posts} - массив объектов с постами.


Ответы (1 шт):

Автор решения: SwaD

В Blog.tsx добавляете функцию

const getNewFilter = (filter: TypeFiltered) => {
    // Получен новый фильтр, обрабатывайте
}

и передаем ее в компонент Filter

<Filter change={getNewFilter} />

в Filter.tsx Указываете пропс и обработчик события, например useEffect, что бы отслеживать изменение состояния filrted

export const Filter = ({ change }: { change: (newFilter) => void }) => {

useEffect(() => {
    change(filtred);
}, [filtred]);

change: (newFilter) => void - Вот это по хорошему должно выглядеть так change: (newFilter: TypeFiltered) => void где TypeFiltered это описанный тип для filtred. с функцией getNewFilter аналогично.

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

→ Ссылка