Существуют ли альтернативы querySelectorAll в React?

#javascript #reactjs

#javascript #reactjs

Вопрос:

Я пытаюсь реорганизовать некоторые коды javascript с помощью React. Что я пытаюсь сделать, так это -> У меня есть несколько элементов с одинаковым именем класса, и я хочу иметь контроль над каждым элементом. Для этого в javascript я мог бы просто использовать функции querySelectorAll и forEach, например

 <Svg>
   <circle cx="100" cy="60" r="20" class="human"></circle>
   <line x1="100" y1="80" x2="100" y2="120" class="human"></line>
   <line x1="70" x2="100" y1="75" y2="95" class="human"></line>
   <line x1="130" x2="100" y1="75" y2="95" class="human"></line>
   <line x1="70" x2="100" y1="140" y2="120" class="human"></line>
   <line x1="130" x2="100" y1="140" y2="120" class="human"></line>
</Svg>

const wrongLetters = [];
window.addEventListener('keydown", (e) => {
  if(e.keyCode >= 65 amp;amp; e.keyCode <= 90) {
    wrongLetters.push(e.key)
  }
}

const humans = documentSelectorAll(".human")
humans.forEach((human, index) => {
if (index < wrongLetters.length) {
    human.style.display = "block";
  }
  if (6 === wrongLetters.length) {
    popUpContainer.style.display = "flex";
    comment.innerText = "You have lost";
  }
}); }
  

Однако я предполагаю, что в React все будет по-другому, даже если я изменю ‘class’ на ‘className’? Для этого я уже просмотрел несколько соответствующих сообщений и попытался использовать ‘ref’, но все еще не знаю точно, что делать в этом случае.
Любой совет был бы оценен.

редактировать / Что я пытаюсь сделать, так это каждый раз, когда я добавляю элемент в массив ‘wrongLetters’, будет отображаться каждый элемент в теге Svg. Для каждого элемента Svg по умолчанию установлено значение ‘display: none’ в javascript

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

1. Обычно вы не взаимодействуете с DOM в react. Трудно дать правильный ответ, поскольку мы не знаем, что именно вы пытаетесь сделать.

2. Это действительно зависит от содержимого do what I want here in Javascript , можете ли вы немного уточнить, что вы хотели бы там сделать?

3. В react у вас будет компонент, который отображает эти элементы, обновляя их или отображая разные элементы в соответствии с изменениями в приложении или состоянии компонента. Вам очень, очень редко требуется обращаться к DOM напрямую в react.

4. @CertainPerformance Спасибо, что я отредактировал свой пост

5. @Junyoung Посмотрите мой ответ и рабочую демонстрацию, чтобы понять, что я имею в виду.

Ответ №1:

Переведите wrongLetters в состояние, которое будет изменено, вместо отправки в массив. Затем в React проанализируйте это состояние, чтобы определить, сколько элементов нужно скрыть. Поскольку это может охватывать все функции, которые вы ищете, нет необходимости иметь доступ к отдельным элементам DOM с помощью useRef или querySelectorAll :

 const App = () => {
    const [pressed, setPressed] = React.useState([]);

    React.useEffect(() => {
        window.addEventListener('keydown', (e) => {
            if (!pressed.includes(e.keyCode) amp;amp; e.keyCode >= 65 amp;amp; e.keyCode <= 90) {
                setPressed(pressed => [...pressed, e.keyCode]);
            }
        });
    }, []);
    return (
        <svg>
            <circle style={{display: pressed.length > 5 ? 'block' : 'none'}} cx="100" cy="60" r="20" stroke="black"></circle>
            <line style={{display: pressed.length > 4 ? 'block' : 'none'}} x1="100" y1="80" x2="100" y2="120" stroke="black"></line>
            <line style={{display: pressed.length > 3 ? 'block' : 'none'}} x1="70" x2="100" y1="75" y2="95" stroke="black"></line>
            <line style={{display: pressed.length > 2 ? 'block' : 'none'}} x1="130" x2="100" y1="75" y2="95" stroke="black"></line>
            <line style={{display: pressed.length > 1 ? 'block' : 'none'}} x1="70" x2="100" y1="140" y2="120" stroke="black"></line>
            <line style={{display: pressed.length > 0 ? 'block' : 'none'}} x1="130" x2="100" y1="140" y2="120" stroke="black"></line>
        </svg>
    );
}
ReactDOM.render(<App />, document.querySelector('.react'));  
 line {
  color: black;
}  
 <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div class='react'></div>  

Это способ реагирования — используйте state, когда можете; избегайте прямого доступа / изменения DOM, просто заставьте рендеринг отражать состояние и изменять состояние при необходимости.

Ответ №2:

Как я уже говорил в своем комментарии, в react у вас будет компонент, который отображает эти элементы, обновляя их или отображая разные элементы в соответствии с изменениями в приложении или состоянии компонента. Вам очень, очень редко требуется обращаться к DOM напрямую в react.

Вот примерная реализация того, что я имею в виду. На codesandbox есть его живая / рабочая копия:

 import React, { useEffect } from "react";
import "./styles.css";

// an array of the svg elements; the component below renders
// a subset of these according to number of attempts.
// i'm not sure this is how i'd do this in the real world
// but it's good enough for this demo.
const segments = [
  <circle cx="100" cy="60" r="20" class="human"></circle>,
  <line x1="100" y1="80" x2="100" y2="120" class="human"></line>,
  <line x1="70" x2="100" y1="75" y2="95" class="human"></line>,
  <line x1="130" x2="100" y1="75" y2="95" class="human"></line>,
  <line x1="70" x2="100" y1="140" y2="120" class="human"></line>,
  <line x1="130" x2="100" y1="140" y2="120" class="human"></line>
];

export default function App() {
  // track the number of attempts in component state
  const [attempts, setAttempts] = React.useState(0);

  // handler for keydown events that for this demo
  // doesn't do anything besides increment the number of attempts
  const onKeyDown = React.useCallback(() => setAttempts(attempts   1), [
    attempts
  ]);

  useEffect(() => {
    // when the component mounts, add the keydown listener
    window.addEventListener("keydown", onKeyDown);

    // when the component unmounts remove the listener
    return () => window.removeEventListener("keydown", onKeyDown);
  }, [onKeyDown]);

  // get the visible subset of segments based on number of attempts
  const visibleSegments = segments.slice(0, attempts);

  // return the new markup
  return (
    <div className="App">
      <svg viewBox="0 0 200 200" style={{ width: "300px" }}>
        {visibleSegments}
      </svg>
      {attempts >= segments.length amp;amp; (
        <div>
          <div>You Lose or whatever</div>
          <button onClick={() => setAttempts(0)}>Reset</button>
        </div>
      )}
    </div>
  );
}
  

Ответ №3:

Брат, если ты хочешь получить доступ к DOM в React JS, тебе нужно создать ссылку с помощью крючков createRef(), и тогда ты сможешь получить доступ к Dom в react как javascript

 class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}  

вы можете получить доступ к узлу, вызвав этот метод.myRef.current

 const node = this.myRef.current;  

Вы можете добавить одну и ту же ссылку в несколько html-элементов, и когда вы вызываете this.myRef.current, тогда ко всем элементам, которые вы помещаете в ссылку, вы можете получить доступ…