querySelector вернул пустой элемент

#javascript #reactjs

#javascript #reactjs

Вопрос:

У меня проблема в том, что когда мой код автоматически обновляется после сохранения файла в VS Code theText и theBtn возвращает целевые элементы, а на странице отображается содержимое, и все работает нормально. Но всякий раз, когда я обновляю страницу вручную, на странице отображается содержимое, но когда я нажимаю theBtn элемент, чтобы развернуть текст, theText и theBtn становится пустым, и страница завершается ошибкой с сообщением «невозможно прочитать свойство undefined».

Я пытался найти причину, но не смог. Кто-нибудь, пожалуйста, помогите. Спасибо.

 import { React, useEffect, useState } from 'react';
    import places from '../data/places';


const Tours = () => {
return (
    <>
        <div className="my-20 mx-auto bg-blue-100 " style={{ height: "100%" }}>
            <h1 className="text-5xl capitalize text-center font-semibold">our tours</h1>
            <hr className="w-20 place-self-center mx-auto border-2 mb-12 mt-2 border-green-600" />
            <Tuor cTime={new Date().getTime().toString()} />
        </div>
    </>
)
}

const Tuor = (props) => {

const [tuors, setTours] = useState(places);

 const theText = document.querySelectorAll(".theText")
 const theBtn = document.querySelectorAll(".theBtn")
        console.log(theText);
        console.log(theBtn);


const expandText = (index) => {

    if (theBtn[index].innerHTML === "read more") {
        theText[index].style.maxHeight = "50rem";
        theBtn[index].innerHTML = "show less";
    } else if (theBtn[index].innerHTML === "show less") {
        theText[index].style.maxHeight = "6rem";
        theBtn[index].innerHTML = "read more";

    }
}

const removePlace = (id) => {
    const newTours = tuors.filter((place) => {
        return place.id !== id;
    });
    setTours(newTours);
}
return (
    <>
        {
            tuors.map((place, index) => {
                let price = new Intl.NumberFormat().format(place.price);
               
                return (
                    <>
                        <div key={index} className="flex flex-col w-2/4 mx-auto bg-white shadow-2xl mb-10">

                            <div>
                                <img src={place.image} alt={place.title} />
                            </div>

                            <div className="flex mt-10">
                                <div className="flex justify-start w-3/4 pl-10">
                                    <p className="tracking-widest capitalize font-bold">{place.title}</p>
                                </div>
                                <div className="flex justify-end w-1/4 pr-10"><p className="bg-blue-50 tracking-wider p-1 rounded-lg font-bold text-blue-400">N{price}</p></div>
                            </div>
                            <div className="my-5 px-10 py-2">
                                <p className="text-gray-500 theText">{place.description}</p><button className="text-blue-500 capitalize theBtn" onClick={() => expandText(index)}>read more</button>
                            </div>
                            <button className="ring-1 ring-red-600 text-red p-1 rounded-sm w-48 mx-auto capitalize my-12" onClick={() => removePlace(place.id)}>not interested</button>
                        </div>

                    </>
                )
            })
        }
    </>
)
}


export default Tours;
 

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

1. что такое идентификатор места?

2. идентификатор места — это число (от 1 до 9). импортированный модуль places представляет собой массив объектов

3. Эй, не могли бы вы, пожалуйста, создать изолированную среду кода для лучшего понимания? Здесь, codesandbox.io/

4. codesandbox.io/s/wizardly-lichterman-y93n5?file=/src/tuors.js вот ссылка на код в condesandbox.

Ответ №1:

Используйте getElementsByClassName вместо querySelectorAll , поскольку он выдает object вместо array of elements при первоначальном рендеринге.

Я нахожу это поведение действительно странным, но когда я прочитал об этом, я узнал о

Поскольку querySelectorAll() возвращает список, который является статическим с момента его вызова, его список элементов не может быть обновлен после этого, даже если изменения вносятся в DOM динамически. Сравните это с getElementsByClassName() , который возвращает совпадающие наборы элементов в любой момент, когда он вызывается. Если вы вносите изменения в DOM «на лету», список, возвращаемый getElementsByClassName(), будет обновляться динамически.

  • querySelectorAll ВОЗВРАТ static NodeList object
  • getElementsByClassName возвращает HTML Collection динамический

Вот ссылка на код: https://codesandbox.io/s/mystifying-wood-slqs4?file=/src/tuors.js

You can read more about differences at https://unicorntears.dev/posts/queryselectorall-vs-getelementsbyclassname/

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

1. Большое вам спасибо. Это действительно сработало. Мне было бы очень сложно разобраться в этом. Еще раз спасибо за ссылку, чтобы прочитать разницу. Я уверен, что так и будет.

2. Приятно слышать, что это действительно помогло. Добро пожаловать 🙂

3. Я вижу, что вы использовали useEffect() empty, почему это было? И useRef() cnt.current, который я console.log извлек, возвращал 1 каждый раз, когда я запускал код. Не могли бы вы объяснить, почему вы это использовали? Спасибо

4. Я отлаживал, поэтому добавил его. Нет необходимости его использовать. Вы можете удалить его.

5. Хорошо, спасибо за добрые и полезные ответы.