Проблема с запуском нескольких обновлений высоты с помощью использования реакции-пружины Переход массива элементов - PullRequest
0 голосов
/ 04 августа 2020

Я пытаюсь построить HO C, который бы анимировал детей с заданным набором типов анимации. Все работает хорошо, за исключением случая, когда useTransition применяется к массиву item s, которые являются material-ui Accordion s.

HO C обрабатывает как логические, так и ключевые элементы на основе массива, направляя их в useSpring или useTransition соответственно.

Проблема: Когда useTransition применяет стиль высоты к анимации, эта высота не обновляется при открытии Accordion и закрывается. Интересно, что если что-то еще вызывает повторную визуализацию, она с опозданием анимируется должным образом.

Нужно ли принудительно повторять визуализацию? Если да, то где мне разместить этот код?

Animate. js (HO C)

import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { animated, useSpring, useTransition } from 'react-spring';

import { animationStyles } from 'data';

import styles from './Animate.module.scss';

const types = {
  TOP: {
    from: animationStyles.enterTop.from,
    enter: animationStyles.enterTop.enter,
    leave: animationStyles.leaveTop.leave,
  },
  LEFT: {
    from: animationStyles.enterLeft.from,
    enter: animationStyles.enterLeft.enter,
    leave: animationStyles.leaveRight.leave,
  },
  FADE: {
    from: animationStyles.enterFade.from,
    enter: animationStyles.enterFade.enter,
    leave: animationStyles.leaveFade.leave,
  },
  HEIGHT: {
    from: animationStyles.enterHeight.from,
    enter: animationStyles.enterHeight.enter,
    leave: animationStyles.enterHeight.leave,
  },
};

export const Animate = ({
  children,
  type = 'TOP',
  omit = [],
  condition,
  idKey,
  render,
  props,
  style,
}) => {
  const uType = type.toUpperCase();
  const animateHeight = omit?.map(v => v.toUpperCase()).indexOf('HEIGHT') === -1;
  const isList = Array.isArray(condition);

  const [refMap] = useState(new WeakMap());

  const [show, set] = useState(false);
  useEffect(() => {
    if (isList) return;
    set(condition ?? true);
  }, [show, condition, isList]);

  const heightProps = item => {
    const ref = refMap.get(item);
    if (!ref) return {};
    const height = ref.offsetHeight;
    return {
      from: animateHeight ? { height: 0 } : {},
      enter: animateHeight ? { height } : {},
      update: animateHeight ? { height } : {},
      leave: animateHeight ? { height: 0 } : {},
    };
  };

  const from = { ...types[uType].from, ...props?.from };
  const enter = { ...types[uType].enter, ...props?.to };
  const to = show ? enter : from;

  const springProps = useSpring({ from, to });

  const transitions = useTransition(condition, item => item[idKey], {
    from: item => ({ ...from, ...heightProps(item).from, overflow: 'hidden' }),

    update: item => async next => {
      const props = { ...enter, ...heightProps(item).update, overflow: 'visible' };
      return await next(props);
    },
    leave: item => async next => {
      const props = { ...from, ...heightProps(item).leave, overflow: 'hidden' };
      return await next(props);
    },
    unique: true,
  });

  return isList ? (
    transitions.map(({ item, props, key }) => (
      <animated.div key={key} style={props} className={classnames(styles.root, style)}>
        <div ref={ref => ref && refMap.set(item, ref)}>{render(item)}</div>
      </animated.div>
    ))
  ) : (
    <animated.div style={springProps} className={classnames(styles.root, style)}>
      <div>{children}</div>
    </animated.div>
  );
};

Animate.propTypes = {
  children: PropTypes.node,
  render: PropTypes.func,
  omit: PropTypes.array,
  type: PropTypes.string,
  condition: PropTypes.oneOfType([PropTypes.bool, PropTypes.array]),
  props: PropTypes.object,
  idKey: PropTypes.string,
  style: PropTypes.string,
  expanded: PropTypes.bool,
};

export default Animate;

Пример использования.

const renderItem = subId => (
      <Accordion
        key={subId}
        expanded={expanded === subId}
        onChange={onChange(subId)}
      >
        <AccordionSummary expandIcon={<ExpandMoreIcon />}>
          <InfoTitles titles={titles} style={styles.infoTitles} />
          {action && (
            <AppButton onClick={action.func} />
          )}
        </AccordionSummary>
        <AccordionDetails>{children}</AccordionDetails>
      </Accordion>
);


return <Animate
  style={styles.animateRoot}
  condition={Object.keys(itemList).map(v => ({ subId: v }))}
  idKey="subId"
  type="left"
  render={item => renderItem(item.subId)}
/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...