как правильно вырезать методом 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"><</button>
<button onClick={(evt) => btnNext(evt)} className="nav-switches-cards__button nav-switches-cards__button_right">></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>
Ответы (2 шт):
Благодаря ссылке, любезно предоставленной @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 Опытные разрабы, поправьте меня, пожалуйста, где можно сделать лучше или где неправильно трактую мысли в комментариях.
Решил проблему более изящным способом, как мне кажется. Вся функциональность была переведена в компонент кнопок. Так компонент в разы проще интегрируется в другие части страницы.
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)}
><
</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)}
>>
</button>
</nav>
);
}
export default NavSwitchesCards;


