Реакция: могу ли я изменить состояние (useState), не вызывая перерисовку, чтобы я мог видеть переход css? - PullRequest
1 голос
/ 13 января 2020

У меня есть разные «карты», которые при клике onClick я хочу, чтобы их свойство margin-left было изменено

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

Приведенный ниже пример кода показывает проблему, но упрощенная версия, не имеющая компонента <Type> и использующая простой массив elements, работает как ожидалось

Итак, если мне нужно использовать структуру, подобную приведенной ниже, как я могу сохранить эффект перехода?

Пример кода

https://codesandbox.io/s/keen-shadow-2v16s?fontsize=14&hidenavigation=1&theme=dark

import React, { useState } from "react";
import styled from "@emotion/styled";

export default function App() {
  const [userTap, setUserTap] = useState({});
  const elements1 = [...Array(5)];
  const elements2 = [...Array(3)];

  const Type = ({ list }) =>
    list.map((el, i) => (
      <Ingredient
        key={"draggable" + i}
        onClick={e => {
          e.stopPropagation();
          e.preventDefault();
          userTap[i] = userTap[i] ? 0 : 1;
          setUserTap({ ...userTap }); // create a new ref to provoke the rerender
          return;
        }}
        userTap={userTap[i]}
      >
        <div>item</div>
      </Ingredient>
    ));

  return (
    <>
      <Type list={elements1} />
      <Type list={elements2} />
    </>
  );
}

const Ingredient = styled.li`
  list-style: none;
  cursor: pointer;
  margin: 5px;
  padding: 5px;
  background: #ccc;
  border-radius: 3px;
  width: 50px;
  margin-left: ${props => (props.userTap ? "100px" : "15px")};
  transition: all 0.2s ease-in;
`;

1 Ответ

2 голосов
/ 13 января 2020

Единственное, что нужно сделать, как @larz предложил в комментариях, это переместить useState к последнему компоненту, как показано ниже

https://codesandbox.io/s/affectionate-hawking-5p81d?fontsize=14&hidenavigation=1&theme=dark

import React, { useState } from "react";
import styled from "@emotion/styled";

export default function App() {
  const elements1 = [...Array(5)];
  const elements2 = [...Array(3)];

  const Type = ({ list, type }) => {
    const [userTap, setUserTap] = useState({});
    return list.map((el, i) => (
      <Ingredient
        key={"draggable" + i}
        onClick={e => {
          e.stopPropagation();
          e.preventDefault();
          userTap[type + i] = userTap[type + i] ? 0 : 1;
          setUserTap({ ...userTap }); // create a new ref to provoke the rerender
          return;
        }}
        userTap={userTap[type + i]}
      >
        <div>item</div>
      </Ingredient>
    ));
  };

  return (
    <>
      <Type list={elements1} type="one" />
      <Type list={elements2} type="two" />
    </>
  );
}

const Ingredient = styled.li`
  list-style: none;
  cursor: pointer;
  margin: 5px;
  padding: 5px;
  background: #ccc;
  border-radius: 3px;
  width: 50px;
  margin-left: ${props => (props.userTap ? "100px" : "15px")};
  transition: all 0.2s ease-in;
`;
...