Home > Back-end >  React: Better way to execute goNext and goPrev in a modal
React: Better way to execute goNext and goPrev in a modal

Time:02-20

I have got this UI below. When I first open this component ModalColorList and click goNext(), it does not go next at first but the second time. After that, it goes next well, so it means the user needs to click twice the button in order to go next.

In the case of goPrev() it works fine, but it does not seem to be clean either.

I usually google before beginning to code, but this time, I would like to try by myself, so maybe this does not work as expected. Please let me know the better way to make goPrev and goNext smoother.

enter image description here

ModalColorList

const ModalColorList = ({ data }) => {
  const [isLoading, setIsLoading] = useState(false);
  const [large, setLarge] = useState({
    idx: data?.index,
    name: data?.name,
    src: data?.image,
  });

  const onColorClick = (color, idx) => {
    setLarge({
      idx,
      name: color.node.name,
      src: color.node.imageAttribute.image.mediaItemUrl,
    });
  };

  const goPrev = () => {
    let count = 0;
    if (large.idx === 0) {
      count = data.data.length - 1;
    } else {
      count = large.idx - 1;
    }
    setLarge({
      idx: count,
      name: data?.data[count]?.node.name,
      src: data?.data[count]?.node.imageAttribute.image.mediaItemUrl,
    });
  };

  const goNext = () => {
    let count = data.index  ;

    if (data.index > data.data.length) {
      data.index = 0;
      count = 0;
    }
    setLarge({
      idx: count,
      name: data?.data[count]?.node.name,
      src: data?.data[count]?.node.imageAttribute.image.mediaItemUrl,
    });
  };

  useEffect(() => {
    setIsLoading(true);
  }, []);

  return (
    <>
      {isLoading && (
        <div >
            <div>
              <div onClick={goPrev}>
                <RiArrowLeftSLine />
              </div>
              <div>
                <Image src={large.src} objectFit="cover" />
              </div>
              <div className="icon-wrap -right-[50px]" onClick={goNext}>
                <RiArrowRightSLine />
              </div>
            </div>
            <ul>
              {data.data.map((color, idx) => (
                <li key={color.node.id} onClick={() => onColorClick(color, idx)} >
                  <div className={` ${large.idx === idx && 'border-[#f7941d] border-4'}`}>
                    <Image src={color.node.imageAttribute.image.mediaItemUrl} />
                  </div>
                </li>
              ))}
            </ul>
        </div>
      )}
    </>
  );
};

export default ModalColorList;

Kindly let me

CodePudding user response:

I'm not sure why didn't things didn't work for you, as there was very little code that I could analysis. But till what you have shared, the component should have been working properly.

I have cleaned your work some what and create a codesandbox for the same, hope it gives you some idea.

If this doesn't help, please do share a codesandbox instance where the behavior is reproduceable I will check on it.

CODESANDBOX LINK

ModalColorList.js

    import { useState, useEffect } from "react";

const ModalColorList = ({ data }) => {
  const [isLoading, setIsLoading] = useState(true);
  const [large, setLarge] = useState({
    idx: data?.index,
    name: data?.name,
    src: data?.image
  });

  const onColorClick = (color, idx) => {
    setLarge({
      idx,
      name: color.name,
      src: color.src
    });
  };

  const goPrev = () => {
    let count = 0;
    const collection = data.collection;
    if (large.idx === 0) {
      count = collection.length - 1;
    } else {
      count = large.idx - 1;
    }
    setLarge({
      idx: count,
      name: collection[count].name,
      src: collection[count].src
    });
  };

  const goNext = () => {
    let count = 0;
    const collection = data.collection;
    if (large.idx   1 >= collection.length) {
      count = 0;
    } else {
      count = large.idx   1;
    }
    console.log(collection, count);
    setLarge({
      idx: count,
      name: collection[count].name,
      src: collection[count].src
    });
  };

  return (
    <>
      {isLoading && (
        <div>
          <div>
            <div onClick={goPrev}>Left</div>
            <div onClick={goNext}>Right</div>
            <div>
              <img src={large.src} objectFit="cover" />
            </div>
          </div>
          <ul>
            {data.collection.map((color, idx) => (
              <li key={idx} onClick={() => onColorClick(color, idx)}>
                <div
                  className={` ${
                    large.idx === idx && "border-[#f7941d] border-4"
                  }`}
                >
                  <img src={color.src} />
                </div>
              </li>
            ))}
          </ul>
        </div>
      )}
    </>
  );
};

export default ModalColorList;

colorSample.js

export default {
  name: "glassy",
  src:
    "https://images.unsplash.com/photo-1604079628040-94301bb21b91?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80",
  index: 0,
  collection: [
    {
      name: "glassy",
      src:
        "https://images.unsplash.com/photo-1604079628040-94301bb21b91?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80"
    },
    {
      name: "pop",
      src:
        "https://images.unsplash.com/photo-1498940757830-82f7813bf178?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1074&q=80"
    },
    {
      name: "milky",
      src:
        "https://images.unsplash.com/photo-1556139943-4bdca53adf1e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80"
    }
  ]
};

App.js

import "./styles.css";
import ModalColorList from "./ModalColorList";
import colorSample from "./colorSample";
export default function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <ModalColorList data={colorSample} />
    </div>
  );
}

CodePudding user response:

if you understand you have list and want to navigate with next and pre, simple you can create temp array, use push and pop to add and remove items then always show the last item like that.

yourArray[yourArray.length - 1]

let me show you example.

let currentIndex = 0;
const mylistItem = [1,2,3,4,5];
let showItems = [mylistItem[currentIndex]] // default show first item always showing last item 
const lastItem = showItems[showItems.length - 1]; // the item want to display

for Moving forward

showItems.push(myListItem[currentIndex 1]);
currentIndex  = 1;

for Moving back

showItems.pop();
currentIndex -= 1;
  • Related