#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
Любая помощь приветствуется!
Ответ №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>
);
}