ama icon indicating copy to clipboard operation
ama copied to clipboard

React.useRef situation

Open hrdyjan1 opened this issue 5 years ago • 0 comments

Hi Kent

Intro

It s honor for me to ask you question about React. Well sometimes it s not a problem to solve something in programming like solve it in proper way, to make things work. In my case I figure it out, but it s not perfect, and it feels like you could help me, to make my code better.

Problem Better way to handle carousel without unnecessary rerender.

Solution Learn from others how to keep moving in more React way.

Code

import React, { useState, useRef, useEffect } from 'react';
import { get, noop } from 'lodash';
import Carousel from 'nuka-carousel';
import Card from './Card';

export const slides = [
  {
    id: 1,
    header: 'Rohlík.cz',
  },
  {
    id: 2,
    header: 'Škoda Auto',
  },
  {
    id: 3,
    header: 'ČEZ',
  }
];

const CardCarousel = ({ carouselRef }) => (
  <Carousel ref={carouselRef} wrapAround withoutControls>
    {slides.map(slide => <Card slide={slide} key={slide.id} />)}
  </Carousel>
);

const CardsWrapper = ({ carouselRef, slideIndex, previousSlide, nextSlide }) => (
  <>
    <CardCarousel carouselRef={carouselRef} />
    <button type="button" onClick={previousSlide}>&lt;</button>
    <p>{`${slideIndex + 1}/${slides.length}`}</p>
    <button type="button" onClick={nextSlide}>&gt;</button>
  </>
);

// Because of useRef this does not work well with useEffect,
// so we need to trigger rerender with toggle `actualization`
const Cards = () => {
  const carouselRef = useRef();
  const nextSlide = get(carouselRef.current, 'nextSlide', noop);
  const previousSlide = get(carouselRef.current, 'previousSlide', noop);
  const slideIndex = get(carouselRef.current, 'state.currentSlide', 0);

  // Next line should be something different
  const [actualization, setActualization] = useState(false);
  const [index, setIndex] = useState(slideIndex);

  useEffect(() => {
    const newIndex = get(carouselRef.current, 'state.currentSlide', 0);
    setIndex(newIndex);
  }, [actualization]);

  // Only works as toggle
  const actualizeCard = () => {
    setActualization(!actualization);
  };

  const next = () => {
    nextSlide();
    actualizeCard();
  };

  const previous = () => {
    previousSlide();
    actualizeCard();
  };

  const cardCarouselProps = {
    slides,
    carouselRef,
    slideIndex: index,
    nextSlide: next,
    previousSlide: previous,
  };

  return <CardsWrapper {...cardCarouselProps} />;
};

export default Cards;

TL;DR If you ever visit Czech Republic, let me know to say hi, I ll show you the beauty of Prague.

hrdyjan1 avatar Nov 29 '19 20:11 hrdyjan1