#javascript #html #css #reactjs
Вопрос:
Я хочу создать функцию, которая повторяет все элементы с одним и тем же классом, и удаляет определенный класс.
Это можно было бы легко сделать с помощью JavaScript.
const boxes = document.querySelectorAll(".box1");
function remove_all_active_list() {
boxes.forEach((element) => element.classList.remove('active'));
}
Но как я могу сделать эту похожую вещь, как я реагирую. Проблема, с которой я сталкиваюсь, заключается в том, что я не могу использовать document.querySelectorAll(".box1")
в React, но я могу использовать React.createRef()
, но это дает мне не все элементы, а только последний элемент.
Это мой код реакции
App.js
import React, { Component } from 'react';
import List from './List';
export class App extends Component {
componentDidMount() {
window.addEventListener('keydown', this.keypressed);
}
keypressed = (e) => {
if (e.keyCode == '38' || e.keyCode == '40') this.remove_all_active_list();
};
remove_all_active_list = () => {
// boxes.forEach((element) => element.classList.remove('active'));
};
divElement = (el) => {
console.log(el);
el.forEach((element) => element.classList.add('active'))
};
render() {
return (
<div className="container0">
<List divElement={this.divElement} />
</div>
);
}
}
export default App;
List.js
import React, { Component } from 'react';
import data from './content/data';
export class List extends Component {
divRef = React.createRef();
componentDidMount() {
this.props.divElement(this.divRef)
}
render() {
let listItem = data.map(({ title, src }, i) => {
return (
<div className="box1" id={i} ref={this.divRef} key={src}>
<img src={src} title={title} align="center" alt={title} />
<span>{title}</span>
</div>
);
});
return <div className="container1">{listItem}</div>;
}
}
export default List;
Пожалуйста, скажите мне, как я могу решить эту проблему.
Ответ №1:
Короткий ответ
Ты бы не стал.
Вместо этого вы бы условно добавили и удалили класс в элемент, компонент или collection.map()
внутри вашего компонента React вместо этого.
Пример
Вот пример, который иллюстрирует оба:
import styles from './Example.module.css';
const Example = () => {
const myCondition = true;
const myCollection = [1, 2, 3];
return (
<div>
<div className={myCondition ? 'someGlobalClassName' : undefined}>Single element</div>
{myCollection.map((member) => (
<div key={member} className={myCondition ? styles.variant1 : styles.variant2}>
{member}
</div>
))}
</div>
);
};
export default Example;
Так что в вашем случае:
- Вы можете передать
active
prop<ListItem />
компоненту и использоватьprops.active
его в качестве условия. - В качестве альтернативы вы можете отправить
activeIndex
в<List />
компонент и использоватьindex === activeIndex
в качестве условия на своей карте.
Объяснение
Вместо добавления или удаления классов в элемент HTMLElement react заботится о визуализации и обновлении всего элемента и всех его свойств (включая class
— которые в react вы бы написали как className
).
Не вдаваясь в тень дома и почему реакция может быть предпочтительнее, я просто попытаюсь объяснить изменение в мышлении:
Компоненты не только описывают элементы html, но также могут содержать логику и поведение. Каждый раз, когда какое-либо свойство изменяется, по крайней мере, метод визуализации вызывается снова, и элемент заменяется новым элементом (т. е. Раньше без какого-либо класса, но теперь с классом).
Теперь гораздо проще менять классы. Все, что вам нужно сделать, это изменить свойство или изменить результат условия (оператор if).
Таким образом, вместо того, чтобы выбирать некоторые элементы в dom и применять к ним некоторую логику, вы вообще не будете выбирать какой-либо элемент; логика записана прямо внутри компонента react, рядом с той частью, которая выполняет фактический рендеринг.
Дальнейшее чтение
https://reactjs.org/docs/state-and-lifecycle.html
Пожалуйста, не стесняйтесь добавлять комментарий, если что-то нужно перефразировать или добавить.
Комментарии:
1. не могли бы вы, пожалуйста, объяснить это подробнее, я не понял
2. @ArpitFalcon Я добавил объяснение своими словами, пытаясь объяснить сдвиг в мышлении, и добавил ссылку для дальнейшего чтения. Дайте мне знать, если это поможет вам лучше понять ответ на ваш вопрос.
Ответ №2:
передайте ref
родительский div в List
компоненте.
...
componentDidMount() {
this.props.divElement(this.divRef.current)
}
...
<div ref={this.divRef} className="container1">{listItem}</div>
затем в приложении
divElement = (el) => {
console.log(el);
el.childNodes.forEach((element) => element.classList.add('active'))
}
надеюсь, это сработает. вот простой пример
https://codesandbox.io/s/staging-microservice-0574t?file=/src/App.js
Комментарии:
1. Это наивный подход, и он полностью упускает из виду суть реакции.
2. @Webber я согласен с вами, но вопрос был не в подходе к обработке классов в react, а в том, как он может добавить или удалить какой-либо класс.
3. Я понимаю, но добавление «активного класса» — это, по сути, хрестоматийный пример того, в чем преуспевает react. Я бы счел это неудачной возможностью помочь кому-то научиться, предложив взлом, который, скорее всего, вообще не сэкономит время.
Ответ №3:
App.js
import React, { Component } from "react";
import List from "./List";
import "./styles.css";
export class App extends Component {
state = { element: [] };
ref = React.createRef();
componentDidMount() {
const {
current: { divRef = [] }
} = this.ref;
divRef.forEach((ele) => ele?.classList?.add("active"));
console.log(divRef);
window.addEventListener("keydown", this.keypressed);
}
keypressed = (e) => {
if (e.keyCode == "38" || e.keyCode == "40") this.remove_all_active_list();
};
remove_all_active_list = () => {
const {
current: { divRef = [] }
} = this.ref;
divRef.forEach((ele) => ele?.classList?.remove("active"));
// boxes.forEach((element) => element.classList.remove('active'));
console.log(divRef);
};
render() {
return (
<div className="container0">
<List divElement={this.divElement} ref={this.ref} />
</div>
);
}
}
export default App;
List.js
import React, { Component } from "react";
import data from "./data";
export class List extends Component {
// divRef = React.createRef();
divRef = [];
render() {
let listItem = data.map(({ title, src }, i) => {
return (
<div
className="box1"
key={i}
id={i}
ref={(element) => (this.divRef[i] = element)}
>
<img src={src} title={title} align="center" alt={title} width={100} />
<span>{title}</span>
</div>
);
});
return <div className="container1">{listItem}</div>;
}
}
export default List;
Создайте ссылку для компонента списка и получите доступ к их дочерним элементам. При нажатии клавиши(стрелка вверх/вниз) элементы, имеющие имя класса как «активные», будут удалены. ссылка
Комментарии:
1. да, но я только что добавил решение для его требования. он попросил очистить весь активный класс элемента при нажатии клавиши. ссылка