Динамические состояния с реактивными перехватами

#javascript #reactjs #react-hooks

#javascript #reactjs #реагирующие перехваты

Вопрос:

Я пытаюсь отобразить массив с помощью map() функции, присваивая каждому элементу собственное уникальное имя класса (на основе значения индекса), используя некоторые установленные состояния. Элемент должен менять цвет при нажатии с помощью крючков. Я столкнулся с проблемой, когда className = {"header" {index}.index} задается правильное имя состояния (header0, header1 и т. Д.), Но Соответствует строке, а не именам классов, установленным с теми же именами.

 const data = ["James", "John", "Jessica", "Jamie"];

export default function App() {
  const [header0, setHeader0] = useState("visable");
  const [header1, setHeader1] = useState("visable");
  const [header2, setHeader2] = useState("visable");
  const [header3, setHeader3] = useState("visable");

  const clicked = (index) => {
    if (index === 0) {
      setHeader0("invisible");
    } else if (index === 1) {
      setHeader1("invisible");
    }
    /*Is there an alternative like {setHeader   index} instead of this loop?*/
  };

  return (
    <div className="App">
      <h1>Sample Project</h1>
      {data.map((value, index) => (
        <h1
          className={"header"   { index }.index}
          onClick={() => {
            clicked(index);
          }}
        >
          {/* classname should be the state "header0" but right now its just a string */}
          Hello {value}!
        </h1>
      ))}
    </div>
  );
}
 

Вот изолированная среда кода того, что я пытаюсь, с несколькими комментариями, где что-то идет не так. Правильно ли я решаю эту проблему?
https://codesandbox.io/s/wispy-star-38qvw?fontsize=14amp;hidenavigation=1amp;theme=dark

Редактировать wispy-star-38qvw

Любая помощь приветствуется!

Ответ №1:

Вы могли бы использовать единый массив состояний для видимости.

Кроме того, если вы прячете индекс в HTML dataset элемента, на который нажали data-index , вам не нужно отдельное закрытие / функция для каждого индекса.

 const data = ["James", "John", "Jessica", "Jamie"];

function App() {
  const [visibilities, setVisibilities] = React.useState(() => data.map((x) => true));

  const handleClick = (event) => {
    const index = parseInt(event.currentTarget.dataset.index, 10);
    const newVisibilities = [...visibilities];
    newVisibilities[index] = !newVisibilities[index];
    setVisibilities(newVisibilities);
  };

  return (
    <div className="App">
      {data.map((value, index) => (
        <h1 data-index={index} onClick={handleClick} className={visibilities[index] ? "selected" : undefined}>
          Hello {value}, you are {visibilities[index] ? "visible" : "hidden"}!
        </h1>
      ))}
    </div>
  );
}

ReactDOM.render(<App />, document.querySelector("main")); 
 .selected {
  background: lightgreen;
}

h1 {
  cursor: pointer;
  user-select: none;
} 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
<main></main> 

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

1. Вау, это выглядит действительно чисто. Позволит ли это решение также обновлять CSS? Например, если щелкнуть по Джеймсу, могу ли я установить красный цвет?

2. Конечно, позвольте мне обновить фрагмент, чтобы отразить это.

3. Договорились, @Jschriemer 🙂

Ответ №2:

Вы объявляете 2 аргумента в функции clicked, так e что это фактический индекс.

Должно быть

 const clicked = (index) => {
 

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

1. Ах, я вижу, спасибо! Хорошо, исправил это, так что я получаю правильный индекс onClick. Однако состояние по-прежнему не обновляется.. Это должно быть как-то связано с линией className = {"header" {index}.index} , но я не могу понять, что такое альтернатива

Ответ №3:

Я боюсь, что это не очень хороший подход, но вы можете попробовать это:

 import React, { useState, useEffect } from "react";
import "./styles.css";

const data = ["James", "John", "Jessica", "Jamie"];

export default function App() {
  const headers = [];

  [headers[0], headers[1], headers[2], headers[3]] = [
    useState("visable"),
    useState("visable"),
    useState("visable"),
    useState("visable")
  ]; // each headers[index] is an array with [state, setState function]

  const clicked = (index) => {
    alert("clicked "   index);
    headers[index][1]("invisible");
    /*Is there an alternative like {setHeader   index} instead of this loop?*/
  };

  return (
    <div className="App">
      <h1>Sample Project</h1>
      {data.map((value, index) => (
        <h1
          className={headers[index][0]}
          onClick={() => {
            clicked(index);
          }}
        >
          {/* classname should be the state "header0" but right now its just a string */}
          Hello {value}!
        </h1>
      ))}
    </div>
  );
}

 

ручка кода: https://codesandbox.io/s/agitated-rain-o31ms

Ответ №4:

Вы можете изменить способ преобразования состояния в массив, тогда функция click сделает его невидимым по индексу

 const data = ["James", "John", "Jessica", "Jamie"];

export default function App() {
    const [headersVisible, setHeaderVisible] = useState(
        data.map(() => "visible")
    );

    const clicked = (index) => {
        setHeaderVisible(
            headersVisible.map((val, ix) => (index === ix ? "invisible" : val))
        );
    };

    return (
        <div className="App">
            <h1>Sample Project</h1>
            {data.map((value, index) => (
                <h1
                    key={index}
                    className={headersVisible[index]}
                    onClick={()=>clicked(index)}
                >
                    {/* classname should be the state "header0" but right now its just a string */}
                    Hello {value}!
                </h1>
            ))}
        </div>
    );
}