I have a component that renders multiple things, one of that is an array of spans.
Here is a part of my code:
class MyComponent ... {
private targetSpan = HTMLElement;
componentDidMount() {
//Here I get some data that fills an array that has 6 values
}
...
...
...
private setActive(value) {
let target = this.targetSpan;
if (target.classList.contains('active')) {
target.classList.remove('active');
//do more things
}
else {
target.classList.add('active');
//do even more things
}
}
private splitMyThings() {
const returnThings: any[] = [];
forEach(array, thing => {
returnThings.push(
<span class="thing" onClick={() => this.setActive(thing)} ref={elem => this.targetSpan = elem}>
{thing}
</span>
);
});
}
render() {
...
return <div class="container">
...
<div class="myTargets">
{this.splitMyThings()}
</div>
...
</div>;
}
}
When I watch the result in a Browser, all the spans show up how I want, only thing that doesnt seem to work correctly is the setActive-Function (or even something else?). No matter what span I click, everytime only the last one gets the active-class, I absolutely cant figure out how to fix that.
Hope someone has a quick and simple solution or idea how to achieve that, thanks in advance!
Here's an example of how you should being approaching something like this:
import { Component, render } from 'preact';
const CSS_TEXT = `
.thing {
cursor: pointer;
}
.selected {
color: red;
};
`;
class MyComponent extends Component {
state = {
// index of the selected item -- if your list items can change, you'll want a better identifier, such as the text.
selectedIdx: -1,
array: []
}
componentDidMount() {
// Just creating an array as you mention in the post
this.setState({ array: Array.from({ length: 6 }).map((_, i) => i) });
}
render() {
return (
<div>
<style>{CSS_TEXT}</style>
<ul>
{this.state.array.map((thing, i) => (
<li
class={this.state.selectedIdx == i ? 'selected' : ''}
onClick={() => this.setState({ selectedIdx: i })}
>
{thing}
</li>
))}
</ul>
</div>
);
}
}
render(<MyComponent />, document.getElementById('app'));
Can test it in the Preact REPL
Refs are not the way, nor are DOM APIs like .classList
. You also should not be using a forEach
loop to iterate over one list and populate another -- this is what .map
is for.
Changed up your example slightly for a better demo, (making the array a list instead of spans, adding in CSS for the selected items), but it should be easy to translate back.