Выделите элемент списка, react.js

Я хотел бы сохранить цвет фона и цвет текущего элемента списка, по которому щелкнули мышью. Я сделал это для выделения с помощью CSS с помощью следующего кода:

.segmentsList:hover {
    background: black;
    color: white;
    cursor: pointer;
}

Я попытался прикрепить onClickFunction к событию onClick в li следующим образом:

import React, {Component} from 'react';
import Link from "react-router-dom/es/Link";
import {Button} from 'reactstrap';
import cabeza from '../atlas/json/cabeza.json';

const parte = getParameterByName('parte') || 0;


export default class SegmentsList extends Component {

    onClickFunction(e) {
        console.info(e);
        // e.target.element.class = "newBlackColor";
    }

    render() {


        console.info(cabeza[parte].etiquetas);
        readTextFile(cabeza[parte].etiquetas);

        function readTextFile(url) {
            const rawFile = new XMLHttpRequest();
            rawFile.open("GET", url, false);
            rawFile.overrideMimeType('text/xml; charset=iso-8859-1');
            rawFile.onreadystatechange = function () {
                if (rawFile.readyState === 4) {
                    const text = rawFile.responseText;
                    // console.info(rawFile.responseText);
                    const lines = splitLines(text);
                    // console.info(lines);
                    const words = splitWords(lines[0]);
                    // console.info(words);
                    window.words = words;
                }
                return;

                function splitLines(text) {
                    return text.split('\n');
                }

                function splitWords(line) {
                    return line.split('" "').slice(1);
                }
            };
            rawFile.send();
        }


        return (

            <div>
                <ol>
                    {window.words.map((word, index) =>
                        <li
                            onClick = {this.onClickFunction}
                            className='segmentsList'
                            key = {index}>{word}</li>
                    )}
                </ol>

                <Button
                    color='primary'
                    className='mt-3 ml-3'
                >
                    <Link to='/'/>
                    Volver a la portada
                </Button>
            </div>

        );
    }
}

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}

Когда я нажимаю на элемент списка, консоль говорит:

Uncaught TypeError: Cannot set property 'class' of undefined

И проверяя объект события, мы видим, что цель равна нулю:

target:null

Что я делаю неправильно?

Я также читал:

Цвет фона элемента списка изменений CSS с классом

Как с помощью CSS изменить цвет выделенному элементу списка?

Выделите элемент onClick - React.js

Обновлено:

Я хотел бы выделить нажатый и убрать выделение с предыдущего.

Я написал способ выделить элемент списка и держать его выделенным, пока вы не нажмете на него еще раз:

SegmentsList.js

import React, {Component} from 'react';
import Link from "react-router-dom/es/Link";
import {Button} from 'reactstrap';
import cabeza from '../atlas/json/cabeza.json';
import SegmentsListItem from "./SegmentsListItem";

const parte = getParameterByName('parte') || 0;


export default class SegmentsList extends Component {
    constructor(props) {
        super(props);
    }

    render() {
        console.info(cabeza[parte].etiquetas);
        readTextFile(cabeza[parte].etiquetas);

        function readTextFile(url) {
            const rawFile = new XMLHttpRequest();
            rawFile.open("GET", url, false);
            rawFile.overrideMimeType('text/xml; charset=iso-8859-1');
            rawFile.onreadystatechange = function () {
                if (rawFile.readyState === 4) {
                    const text = rawFile.responseText;
                    // console.info(rawFile.responseText);
                    const lines = splitLines(text);
                    // console.info(lines);
                    const words = splitWords(lines[0]);
                    // console.info(words);
                    window.words = words;
                }
                return;

                function splitLines(text) {
                    return text.split('\n');
                }

                function splitWords(line) {
                    return line.split('" "').slice(1);
                }
            };
            rawFile.send();
        }


        return (
            <div>
                <ol>
                    {window.words.map((word, index) =>
                        <SegmentsListItem word = {word} key = {index}/>
                    )}
                </ol>

                <Button
                    color='primary'
                    className='mt-3 ml-3'
                >
                    <Link to='/'/>
                    Volver a la portada
                </Button>
            </div>

        );
    }
}

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}

SegmentsListItem.js

import React, {Component} from 'react';

class SegmentsListItem extends Component {
    constructor(props) {
        super(props);

        this.state = {highlighted: false};

    }

    highlight = (e) => {
        console.info(e.target.className);
        if (!this.state.highlighted) {
            console.info('highlight');
            e.target.className = 'segmentsListSelected';
        } else {
            console.info('remove highlight');
            e.target.className = 'segmentsList';
        }
        this.setState({highlighted: !this.state.highlighted})
    };

    render() {


        return (
            <li
                onClick = {this.highlight}
                className='segmentsList'
                key = {this.props.index}>{this.props.word}</li>
        );
    };
}

export default SegmentsListItem;

Спасибо за помощь.

Первоначально я отправил ответ, но здесь слишком много неправильного. Здесь вы неправильно используете реакцию, и это большая проблема.

Deadron 09.06.2018 01:00

Привет, просто чтобы уточнить, вы хотите, чтобы элемент списка оставался выделенным? Я согласен с Deadron, что вы не используете React для того, для чего он создан. Я бы использовал встроенный стиль и установил цвета, используя состояние компонентов. Если вы не догадались до сегодняшнего вечера, я отвечу на него рабочим образцом.

sonic_ninja 09.06.2018 01:08
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
2
5 547
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы неправильно используете React, и я бы рекомендовал ОЧЕНЬ потратить некоторое время на чтение документации о том, как следует использовать компонент. При этом, в этом случае вы должны использовать состояние для хранения загружаемых слов, а также для активного выбора. Также НЕ Я повторяю НЕ открыть файл в методе рендеринга! ... Циклов рендеринга может быть много, и это будет означать, что вы открываете файл каждый раз, когда происходит рендеринг, что является плохой идеей.

// these are more helper functions.. either define them on your class or just define them in a helpers/utility file. or just put as a global above the class 
function splitLines(text) {
    return text.split('\n');
}

function splitWords(line) {
    return line.split('" "').slice(1);
}

export default class SegmentsList extends Component {
    constructor(props) {
        super(props);
        this.state = { words: [], activeWord: -1 }
    }
    onClickFunction = (idx) => {
        // set the state to only have a current word selection which will unselect the previous selection
        this.setState({activeWord: idx})
    }

    readTextFile = (url) => {
        const rawFile = new XMLHttpRequest();
        rawFile.open("GET", url, false);
        rawFile.overrideMimeType('text/xml; charset=iso-8859-1');
        rawFile.onreadystatechange = () => {
            if (rawFile.readyState === 4) {
                const text = rawFile.responseText;
                const lines = splitLines(text);
                const words = splitWords(lines[0]);
                this.setState({words});
            }
            return;
        };
        rawFile.send();
    }
    componentDidMount() {
        this.readTextFile(cabeza[parte].etiquetas);
    }
    render() {
        return (
            <div>
                <ol>
                    {this.state.words.map((word, index) =>
                        <li
                          onClick = {this.onClickFunction.bind(null, index)}
                          className = {`segmentsList${this.state.activeWord === index ? ' selected' : ''}`}
                          key = {index}
                        >
                          {word}
                        </li>
                    )}
                </ol>

                <Button
                    color='primary'
                    className='mt-3 ml-3'
                >
                    <Link to='/'/>
                    Volver a la portada
                </Button>
            </div>

        );
    }
}

то последнее, что нужно сделать, это добавить класс для выбора в ваш css

.segmentsList:hover, .segmentsList.selected {
    background: black;
    color: white;
    cursor: pointer;
}

Другие вопросы по теме