Home  >  Q&A  >  body text

React-multi-carousel does not refresh correctly when input data changes

I'm building my first full stack MERN-App and have a "small" question about the React-multi-carousel package.

Here is the screenshot from the front (it is the diary section where you can view all diaries for the selected month (selected month and previous month)):

This is my code: from Diary-Container-Component (this is where the problem arises and using carousel)

import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import Wrapper from "../assets/wrappers/DiaryContainer.js";
import { useSelector } from "react-redux";
import { SingleDiaryEntryDisplay, Loading } from "../components";
import Carousel from "react-multi-carousel";
import "react-multi-carousel/lib/styles.css";
import { useGetAllDiaryQuery } from "../features/api/apiSlice.js";

//carousel
const responsive = {
  superLargeDesktop: {
    // the naming can be any, depends on you.
    breakpoint: { max: 4000, min: 3000 },
    items: 5,
  },
  desktop: {
    breakpoint: { max: 3000, min: 1024 },
    items: 3,
  },
  tablet: {
    breakpoint: { max: 1024, min: 464 },
    items: 2,
  },
  mobile: {
    breakpoint: { max: 464, min: 0 },
    items: 1,
  },
};

const DiaryContainer = ({ lastMonth }) => {
  let { searchValuesDiary } = useSelector((store) => store.allDiary);
  let [localSearchValuesDiary, setLocalSearchValuesDiary] =
    useState(searchValuesDiary);

  // for lastMonth

  const {
    data: diaries,
    refetch,
    isLoading,
    isSuccess,
    isFetching,
    isError,
    error,
  } = useGetAllDiaryQuery(localSearchValuesDiary);

  useEffect(() => {
    setLocalSearchValuesDiary({ ...searchValuesDiary });
    if (lastMonth) {
      setLocalSearchValuesDiary({ ...searchValuesDiary, month: lastMonth });
    }
    refetch();
  }, [searchValuesDiary]);

  if (isLoading || isFetching) {
    <Loading center />;
  }

  // diaries && (diaries.result.length < 4 ? false : true);
  console.log(
    diaries && diaries.result.length,
    `length in diaryContainer ${lastMonth ? "lastmonth" : "month"} `
  );
  if (isSuccess) {
    if (diaries.result.length <= 0) {
      return (
        <Wrapper>
          <div className="no-diaries-container">
            <h2>...no diary entries</h2>
          </div>
        </Wrapper>
      );
    }
    return (
      <Wrapper>
        <div className="diary-container">
          <div className="this-month">
            {
              <Carousel
                key={lastMonth ? "Carousel-Last-Month" : "Carousel-First-Month"}
                className="carousel"
                responsive={responsive}
                showDots={diaries && (diaries.result.length < 4 ? false : true)}
              >
                {diaries.result.map((diary) => {
                  const {
                    diaryTitle,
                    mood,
                    performance,
                    createdAt,
                    text,
                    _id: diaryId,
                  } = diary;

                  return (
                    <SingleDiaryEntryDisplay
                      key={diaryId}
                      diaryId={diaryId}
                      title={diaryTitle}
                      createdAt={createdAt}
                      mood={mood}
                      performance={performance}
                      text={text}
                    />
                  );
                })}
              </Carousel>
            }
          </div>
        </div>
      </Wrapper>
    );
  }
};

export default DiaryContainer;

I also modified the point and arrow position in the css (but even after removing this customization, the problem still occurs. So I don't think it is related to the error).

mistake: Every time when I change the filter from June to May (so in the bottom section, the month changes from March to April), April now doesn't show any dots or arrows, despite having about 10 items.

When I refresh the page and select May it works fine and when I want between months (except the change from June to May).

When I remove this code snippet (diaries && (diaries.result.length < 4 ? false : true) and just use true, the app even breaks and gives the output: array Component point with invalid length cannot be loaded.

It seems to me that the carousel is not refreshing/rerendering correctly.

So when June is selected, there is only one item at the bottom for May (so the dot and arrow should not be displayed). Then when I change to May, April is now at the bottom, the injected dataset is correct (it shows items for April), but now the dots and arrows are still disabled, but since there are 10 items, it should Enable.

I've tried a lot of refetching in useEffect and setState hooks to force rerendering and refresh correctly, but the carousel doesn't refresh.

I even placed a key prop on almost every component. But the bug still exists.

Does anyone have a solution to this problem? Maybe my code is so poorly structured (I'm a beginner) that this error isn't known in production.

Thank you for your help.

P粉057869348P粉057869348236 days ago577

reply all(1)I'll reply

  • P粉764003519

    P粉7640035192024-01-29 19:19:35

    You can create an if in a reactive constant, for example

    superLargeDesktop: {
        breakpoint: { max: 4000, min: 3000 },
        items: data.length < 5 ? data.length : 5, 
      },

    I had a similar problem but I used custom dots , If the above code doesn't work try this and add the value in the constant carouselItem< /strong> (Example React multi carousel provider (see documentation), trying to use an array with numbers smaller than the data variable, something like const carouselItems = ['']; , when my file looks like this

    export const CustomDot = ({ onClick = () => {}, ...rest }) => {
      const {
        onMove,
        index,
        active,
        carouselState: { currentSlide, deviceType },
        data,
      } = rest;
    //here you choose the number  equal or smaller than your data length, like 1
      const carouselItems = [''];
      // onMove means if dragging or swiping in progress.
      // active is provided by this lib for checking if the item is active or not.
      return (
        <button
          className={active ? "active" : "inactive"}
          onClick={() => onClick()}
        >
                {React.Children.toArray(carouselItems)[index]}
        </button>
      );
    };

    reply
    0
  • Cancelreply