как правильно вырезать методом splice кусок массива хуками промежутками [el1 +=el1, el2 +=el2]

У меня проблема заключается в том, что есть компонент контейнер News, который отвечает за показ карточек с новостями CardNews. В компоненте есть элемент навигации NavSwitchesCards c 2мя кнопками "<" ">" этим кнопкам из компонента-контейнера News передаются функции колбеки, которые я и не могу правильно написать. Вопрос состоим в том, что у меня хуки стейты,

  const [t1, setT1] = useState(1);
  const [t2, setT2] = useState(3);

которые задают начальные числа, которые впоследствии будут переданы в функции, а в функциях будут вырезать методом splice кусок массива, для отображения новых карточек в компонте News. при первом вызове функции, которые отвечает за отображение нового куска массива хуки useState принимают значения объявленные в начале функции, а должны отработать как setT1(t1 +1); setT2(t2 + 1). Подскажите, пожалуйста, как правильно реализовать эту идею.

Массив приходит из другого каталога

import {arrWithNewsCompany} from '../../utils/arrWithNewsCompany';

Он имеет вид

export const arrWithNewsCompany = [
{
    srcImage: require('../images/image_card_news_1.png').default,
    dataNews: '24 марта',
    title: 'Наш курительный клуб ежедневно работает с 16:00'
  },
  ...
]

Весь код выглядит так

function News() {
  const [t1, setT1] = useState(0);
  const [t2, setT2] = useState(3);
  const [cardsNewsPeace, setCardsNewsPeace] = useState(arrWithNewsCompany.slice(t1, t2));

  function prevImage(evt) {
    evt.preventDefault();
    console.log('prev');
    setT1(prev => prev - 1);
    setT2(prev => prev - 1);
    setCardsNewsPeace(arrWithNewsCompany.slice(t1, t2));
  }

  function nextImage(evt) {
    evt.preventDefault();
    console.log('next');
    setT1(t1 + 1);
    setT2(t2 + 1);
    console.log(t1, t2)
    setCardsNewsPeace(arrWithNewsCompany.slice(t1, t2));
  }

  return (
    <section className="news">
    <div className="news__nav-wrapper">
      <h1 className="news__title">Новости</h1>
      <NavSwitchesCards
        btnPrev={prevImage}
        btnNext={nextImage}
      />
    </div>
      <div className="news__cards">
      {cardsNewsPeace.map((cardNews, index) => {
        return (
          <NewsCard 
            dataCard={cardNews} 
            key={index}
          /> 
        );
      })}
      </div>
    </section>
  );
}

export default News;

Компонент NavSwitchesCards

<nav className="nav-switches-cards" style={style}>
  <button onClick={(evt) => btnPrev(evt)} className="nav-switches-cards__button nav-switches-cards__button_left">&#60;</button>
  <button onClick={(evt) => btnNext(evt)} className="nav-switches-cards__button nav-switches-cards__button_right">&#62;</button>
</nav>

Компонент CardNews

<article className="news-card">
      <img className="news-card__image" src={dataCard.srcImage} alt="Новостная картинка" />
      <div className="news-card__block-text">
        <span className="news-card__data">{dataCard.dataNews}</span>
        <p className="news-card__title">{dataCard.title}</p>
      </div>
    </article>

Верстка компонента News


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

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

Благодаря ссылке, любезно предоставленной @Grundy, решил проблему.

Код прикладываю (в нём предусмотренны комментарии):

import { useEffect, useState, useReducer } from 'react';
import './News.css';
import NewsCard from '../NewsCard/NewsCard';
import NavSwitchesCards from '../NavSwitchesCards/NavSwitchesCards';
import {arrWithNewsCompany} from '../../utils/arrWithNewsCompany';

// как я понял проблема была в том, что при обновлении стейта, необходим был перерендеринг компонента
// либо необходимо было изменять кусок массива непосредственно в ренедере самих DOM объектов
// p.s поправьте, пожалуйста, как правильнее выразить мою мысль
function News({countCardOnPage}) {
  //в этих стейтах будут кнопки "<" и ">" значения в эти стейты записываются после рендеринга всего компонента
  //т.е в useEffect
  const [btnNextImage, setBtnNextImage] = useState();
  const [btnPrevImage, setBtnPrevImage] = useState();
  //создаю useReducer скажу честно, еще не полностью разобрался как он работает, впервые применяю его
  // вычитал его на этом сайте https://build-in-saratov.com/reasons-to-use-usereducer/
  //в кратце он работает так: в state задается начальное значение, если мы ходим повлиять на стейт как то
  // то в моем случае у меня это будет делать handlerBtnClick при каком то условии
  // при этом handlerBtnClick передается как колбэк
  //а непосредственно чтобы вызвать колбек используется dispatch
  // поправьте, если где-то несу чушь
  const [state, dispatch] = useReducer(handlerBtnClick, { startIndex: 0, lastIndex: countCardOnPage});

  //колбэк ф-я для useReducer
  function handlerBtnClick(state, btnClick) {
    switch (btnClick) {
      case '>': return { startIndex: state.startIndex + 1, lastIndex: state.lastIndex + 1};
      case '<': return { startIndex: state.startIndex - 1, lastIndex: state.lastIndex - 1};
      default: return state;
    }
  }

  //ф-я для отключения кнопки
  const disableBtn = (btn) => {
    btn.disabled = true;
    btn.classList.add('nav-switches-cards__button_disabled-style');
  }
//ф-я для вкл кнопки
  const enabledBtn = (btn) => {
    btn.disabled = false;
    btn.classList.remove('nav-switches-cards__button_disabled-style');
  }

  function prevImage() {
    if (state.startIndex === 0) return disableBtn(btnPrevImage);
    enabledBtn(btnNextImage)
    dispatch(btnPrevImage.textContent);
  }

  function nextImage() {
    if (state.lastIndex === arrWithNewsCompany.length) return disableBtn(btnNextImage);
    enabledBtn(btnPrevImage);
    dispatch(btnNextImage.textContent);
  }

  useEffect(() => {
    setBtnNextImage(document.getElementById('nav-switches-cards-btn-next'));
    setBtnPrevImage(document.getElementById('nav-switches-cards-btn-prev'));
    btnPrevImage !== undefined && disableBtn(btnPrevImage);
  }, [btnPrevImage])

  return (
    <section className="news">
    <h1>{state.startIndex}</h1>
    <h1>{state.lastIndex}</h1>
    <div className="news__nav-wrapper">
      <h1 className="news__title">Новости</h1>
      <NavSwitchesCards
        btnPrevImage={prevImage}
        btnNextImage={nextImage}
      />
    </div>
      <div className="news__cards">
      {arrWithNewsCompany.slice(state.startIndex, state.lastIndex).map((cardNews, index) => {
        return (
          <NewsCard 
            dataCard={cardNews} 
            key={index}
          /> 
        );
      })}
      </div>
    </section>
  );
}

export default News;

введите сюда описание изображения


PS Опытные разрабы, поправьте меня, пожалуйста, где можно сделать лучше или где неправильно трактую мысли в комментариях.

→ Ссылка
Автор решения: v1ktorbro

Решил проблему более изящным способом, как мне кажется. Вся функциональность была переведена в компонент кнопок. Так компонент в разы проще интегрируется в другие части страницы.

import { useState } from 'react';
import './News.css';
import NewsCard from '../NewsCard/NewsCard';
import NavSwitchesCards from '../NavSwitchesCards/NavSwitchesCards';
import {arrWithNewsCompany} from '../../utils/arrWithNewsCompany';

//countCardOnPage - желаемое количество карточек, которых хочется видеть на странице
function News({countCardOnPage}) {
  //массив с карточками будет приходить из NavSwitchesCards
  const [arrOnRender, setArrOnRender] = useState([]);

  return (
    <section className="news">
    <div className="news__nav-wrapper">
      <h1 className="news__title">Новости</h1>
      <NavSwitchesCards
        countCardOnPage={countCardOnPage}
        arrWIthCards={arrWithNewsCompany}
        setArrOnRender={setArrOnRender}
      />
    </div>
      <div className="news__cards">
      {arrOnRender.map((cardNews, index) => {
        return (
          <NewsCard 
            dataCard={cardNews} 
            key={index}
          /> 
        );
      })}
      </div>
    </section>
  );
}

export default News;

import './NavSwitchesCards.css';
import React, { useEffect, useReducer} from 'react';
/* кнопки наследуют цвет компонента (через пропс style) */

function NavSwitchesCards({style, idBtn, countCardOnPage, arrWIthCards, setArrOnRender}) {
  const [state, dispatch] = useReducer(handlerBtnClick, { startIndex: 0, lastIndex: countCardOnPage});
  //колбэк ф-я для useReducer
  function handlerBtnClick(state, btnClick) {
    switch (btnClick) {
      case '>': return { startIndex: state.startIndex + 1, lastIndex: state.lastIndex + 1};
      case '<': return { startIndex: state.startIndex - 1, lastIndex: state.lastIndex - 1};
      default: return state;
    }
  }

  function handlerNewSliceArr (evt) {
    dispatch(evt.target.textContent)
    setArrOnRender(arrWIthCards.slice(state.startIndex, state.lastIndex));
  }

  useEffect(() => {
    setArrOnRender(arrWIthCards.slice(state.startIndex, state.lastIndex));
  }, []);

  return (
    <nav className="nav-switches-cards" style={style}>
      <button  
        className={`nav-switches-cards__button ${state.startIndex === 0 ? "nav-switches-cards__button_disabled-style" : ""}`}
        id={`btn-${idBtn}-prev`}
        disabled={state.startIndex === 0 ? true : false} 
        onClick={(evt) => handlerNewSliceArr(evt)}
        >&#60;
      </button>
      <button 
        className={`nav-switches-cards__button ${state.lastIndex === arrWIthCards.length ? "nav-switches-cards__button_disabled-style" : ""}`}
        id={`btn-${idBtn}-next`}
        disabled={state.lastIndex === arrWIthCards.length ? true : false} 
        onClick={(evt) => handlerNewSliceArr(evt)} 
        >&#62;
      </button>
    </nav>
  );
}

export default NavSwitchesCards;

введите сюда описание изображения

→ Ссылка