Реагировать: получение индекса отображенных элементов вне компонента

#reactjs

#reactjs

Вопрос:

Я совсем новичок в React и пытаюсь добавить точки разбиения на страницы в компонент carousel, который я создал с помощью react-swipable. Из документации, доступной для прокрутки, я уже реализовал рабочие кнопки next / previous, но я не могу понять, как реализовать точки разбивки на страницы в том же формате.

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

Компонент использует редуктор, и я застрял на получении индекса из отображаемых элементов в инструкции switch и использую его там. Я думаю, что я просто не смотрю в правильном направлении, потому что я перепробовал все, что мог придумать, и часами гуглил, пытаясь найти ответ, не найдя вообще никаких похожих ситуаций / вопросов. У кого-нибудь из вас есть идея о том, как показать правильный слайд в соответствии с нумерацией страниц-нажатой кнопкой? (таким образом, нажатие второй кнопки разбивки на страницы должно показать второй слайд)

Итак, я добавил регистр точек к оператору switch, внутри которого есть оператор if, чтобы решить, следует ли перемещаться в следующем или предыдущем направлении. Затем я хотел, чтобы ‘pos’ изменился на индекс выбранных элементов.

Извините, если это глупый вопрос, я всего лишь новичок, и иногда это немного сбивает меня с толку.

Вот мой код:

 import React, { useState } from "react";
import styled from "styled-components";
import { Swipeable } from "react-swipeable";

const NEXT = "NEXT";
const PREV = "PREV";
const DOT = "DOT";

function getOrder({ index, pos, numItems }) {
  return index - pos < 0 ? numItems - Math.abs(index - pos) : index - pos;
}

const initialState = { pos: 0, sliding: false, dir: NEXT };

const CarouselContainer = styled.ul`
  display: flex;
  transition: ${(props) => (props.sliding ? "none" : "transform 1s ease")};
  transform: ${(props) => {
    if (!props.sliding) return "translateX(calc(-100%))";
    if (props.dir === PREV) return "translateX(calc(2 * (-100%)))";
    return "translateX(0%)";
  }};
`;

function Carousel(props) {
  const [state, dispatch] = React.useReducer(reducer, initialState);
  const numItems = React.Children.count(props.children);
  const index = props.children;

  function Slide(dir) {
    dispatch({ type: dir, numItems });
    setTimeout(() => {
      dispatch({ type: "stopSliding" });
    }, 50);
  }

  const config = {
    onSwipedLeft: () => Slide(NEXT),
    onSwipedRight: () => Slide(PREV),
    preventDefaultTouchmoveEvent: true,
    trackMouse: true,
  };

  return (
    <Swipeable {...config}>
      <div>
        <CarouselContainer dir={state.dir} sliding={state.sliding}>
          {React.Children.map(props.children, (child, index) => (
            <li
              key={index}
              order={getOrder({ index: index, pos: state.pos, numItems })}
              style={{ order: `${getOrder({ index: index, pos: state.pos, numItems })}` }}
            >
              {child}
            </li>
          ))}
        </CarouselContainer>
      </div>

      <ul>
        <li onClick={() => Slide(PREV)}>Vorige</li>
        <li onClick={() => Slide(NEXT)}>Volgende</li>
      </ul>

      <ul className={styles.pagination}>
        {React.Children.map(props.children, (dot, index) => (
          <li
            key={index}
            onClick={() => {
              Slide(DOT);
            }}
          >
          {dot}
          </li>
        ))}
      </ul>
    </Swipeable>
  );
}

function reducer(state, { type, numItems }) {
  switch (type) {
    case "reset":
      return initialState;
    case PREV:
      return {
        ...state,
        dir: PREV,
        sliding: true,
        pos: state.pos === 0 ? numItems - 1 : state.pos - 1,
      };
    case NEXT:
      return {
        ...state,
        dir: NEXT,
        sliding: true,
        pos: state.pos === numItems - 1 ? 0 : state.pos   1,
      };
    case DOT:
      if (state.pos > state.index) {
        return {
          ...state,
          dir: PREV,
          sliding: true,
          pos: state.index,
        };

      if (state.pos < state.index) {
        return {
          ...state,
          dir: NEXT,
          sliding: true,
          pos: state.index,
        };
      }
    case "stopSliding":
      return { ...state, sliding: false };
    default:
      return state;
  }
}

export default Carousel;

  

Комментарии:

1. Почему вы просто не можете передать индекс функции Slide следующим образом: Slide (ТОЧКА, индекс); а затем отправить его в reducer и использовать его где угодно. Будет ли это работать для вас?

2. @Telary Спасибо вам! иногда мне не хватает такой мелочи! Я действительно пробовал это, но допустил ошибку при отправке. Теперь это наконец работает! Я счастлив 🙂

Ответ №1:

подсказка @ Telary помогла мне решить проблему! Я не могу пометить его комментарий как ответ, так что вот он:

 function Carousel(props) {
  const [state, dispatch] = React.useReducer(reducer, initialState);
  const numItems = React.Children.count(props.children);
  const index = props.children;

  function Slide(dir, index) {
    dispatch({ type: dir, numItems, index });
    setTimeout(() => {
      dispatch({ type: "stopSliding" });
    }, 50);
  }

  const config = {
    onSwipedLeft: () => Slide(NEXT),
    onSwipedRight: () => Slide(PREV),
    preventDefaultTouchmoveEvent: true,
    trackMouse: true,
  };

  return (
    <Swipeable {...config}>
      <div>
        <CarouselContainer dir={state.dir} sliding={state.sliding}>
          {React.Children.map(props.children, (child, index) => (
            <li
              key={index}
              order={getOrder({ index: index, pos: state.pos, numItems })}
              style={{ order: `${getOrder({ index: index, pos: state.pos, numItems })}` }}
            >
              {child}
            </li>
          ))}
        </CarouselContainer>
      </div>

      <ul>
        <li onClick={() => Slide(PREV)}>Vorige</li>
        <li onClick={() => Slide(NEXT)}>Volgende</li>
      </ul>

      <ul className={styles.pagination}>
        {React.Children.map(props.children, (dot, index) => (
          <li
            key={index}
            onClick={() => {
              Slide(DOT, index);
            }}
          >
          {dot}
          </li>
        ))}
      </ul>
    </Swipeable>
  );
}

function reducer(state, { type, numItems }) {
  switch (type) {
    case "reset":
      return initialState;
    case PREV:
      return {
        ...state,
        dir: PREV,
        sliding: true,
        pos: state.pos === 0 ? numItems - 1 : state.pos - 1,
      };
    case NEXT:
      return {
        ...state,
        dir: NEXT,
        sliding: true,
        pos: state.pos === numItems - 1 ? 0 : state.pos   1,
      };
    case DOT:
      if (state.pos > state.index) {
        return {
          ...state,
          dir: PREV,
          sliding: true,
          pos: state.index,
        };

      if (state.pos < state.index) {
        return {
          ...state,
          dir: NEXT,
          sliding: true,
          pos: state.index,
        };
      }
    case "stopSliding":
      return { ...state, sliding: false };
    default:
      return state;
  }
}

export default Carousel;