Как преобразовать код Javascript слайдера изображения в reactjs с помощью хуков

#reactjs

#reactjs

Вопрос:

Я пытаюсь преобразовать пример кода JavaScript в ReactJS.

Компилятор не отображает никаких ошибок, но браузер выдает ошибку во время выполнения.

Я использую этот пример, пожалуйста, смотрите ниже.

https://codepen.io/kathykato/pen/prEmKe

Я ожидаю, что он будет работать, как показано в приведенном выше примере, но я получаю небольшие ошибки.

То, что я пробовал до сих пор, приведено ниже

 -------------------------Carousel.js--------------------------


import React, { useState, useEffect } from "react";
import './Carousel.scss'
   
const Carousel = () => {   

  const items = document.querySelectorAll('img');
   const itemCount = items.length;
   const nextItem = document.querySelector('.next');
   const previousItem = document.querySelector('.previous');
   let count = 0;
   
   // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    nextItem.addEventListener('click', showNextItem);
    previousItem.addEventListener('click', showPreviousItem);
    document.addEventListener('keydown', keyPress);
   
    // clean up
    return () => {
    nextItem.removeEventListener('click', showNextItem);
    previousItem.removeEventListener('click', showPreviousItem);
    document.removeEventListener('keydown', keyPress);
  };
})

   function showNextItem() {
     items[count].classList.remove('active');
   
     if(count < itemCount - 1) {
       count  ;
     } else {
       count = 0;
     }
   
     items[count].classList.add('active');
     console.log(count);
   }
   
   function showPreviousItem() {
     items[count].classList.remove('active');
   
     if(count > 0) {
       count--;
     } else {
       count = itemCount - 1;
     }
   
     items[count].classList.add('active');
     console.log(count);
   }
   
   function keyPress(e) {
     e = e || window.event;
     
     if (e.keyCode == '37') {
       showPreviousItem();
     } else if (e.keyCode == '39') {
       showNextItem();
     }
   }
   
  //  nextItem.addEventListener('click', showNextItem);
  //  previousItem.addEventListener('click', showPreviousItem);
  //  document.addEventListener('keydown', keyPress);
  

  return (
   <div className="container">
  <div className="slider">
    <img className="active" src="https://source.unsplash.com/gKk9rpyDryU" alt="Nothing " />
    <img src="https://source.unsplash.com/VFGEhLznjPU"  alt="Nothing"/>
    <img src="https://source.unsplash.com/InR-EhiO_js"  alt="Nothing"/>
  </div>
  <nav className="slider-nav">
    <ul>
      <li className="arrow">
        <button className="previous">
          <span>
            <i className="ion-arrow-left-c"></i>
          </span>
        </button>
      </li>
      <li className="arrow">
        <button className="next">
          <span>
            <i className="ion-arrow-right-c"></i>
          </span>
        </button>
      </li>
    </ul>
  </nav>
</div>
 ); 
  }

  export default Carousel;


Application built with
{
  "react": "16.13.0", 
  "react-dom": "^16.13.0", 
  "react-redux": "^7.2.0",
  "redux": "^4.0.4"
  "@material-ui/core": "^4.9.5"
}
 

Теперь посмотрите на ошибки ниже:

 TypeError: Cannot read property 'addEventListener' of null
(anonymous function)
H:/ReactJs/Source Codes/react-master/react-master/src/components/Sliders/Carousel.js:14
  11 |  
  12 |  // Similar to componentDidMount and componentDidUpdate:
  13 | useEffect(() => {
> 14 |   nextItem.addEventListener('click', showNextItem);
     | ^  15 |   previousItem.addEventListener('click', showPreviousItem);
  16 |   document.addEventListener('keydown', keyPress);
  17 |  
View compiled
commitHookEffectListMount
H:/ReactJs/Source Codes/react-master/react-master/node_modules/react-dom/cjs/react-dom.development.js:19731
  19728 | if ((effect.tag amp; tag) === tag) {
  19729 |   // Mount
  19730 |   var create = effect.create;
> 19731 |   effect.destroy = create();
        | ^  19732 | 
  19733 |   {
  19734 |     var destroy = effect.destroy;
View compiled
commitPassiveHookEffects
H:/ReactJs/Source Codes/react-master/react-master/node_modules/react-dom/cjs/react-dom.development.js:19769
  19766 |       // before calling any create functions. The current approach only serializes
  19767 |       // these for a single fiber.
  19768 |       commitHookEffectListUnmount(Passive$1 | HasEffect, finishedWork);
> 19769 |       commitHookEffectListMount(Passive$1 | HasEffect, finishedWork);
        | ^  19770 |       break;
  19771 |     }
  19772 | }
View compiled
HTMLUnknownElement.callCallback
H:/ReactJs/Source Codes/react-master/react-master/node_modules/react-dom/cjs/react-dom.development.js:188
  185 |     window.event = windowEvent;
  186 |   }
  187 | 
> 188 |   func.apply(context, funcArgs);
      | ^  189 |   didError = false;
  190 | } // Create a global error event handler. We use this to capture the value
  191 | // that was thrown. It's possible that this error handler will fire more
View compiled
invokeGuardedCallbackDev
H:/ReactJs/Source Codes/react-master/react-master/node_modules/react-dom/cjs/react-dom.development.js:237
  234 | // errors, it will trigger our global error handler.
  235 | 
  236 | evt.initEvent(evtType, false, false);
> 237 | fakeNode.dispatchEvent(evt);
      | ^  238 | 
  239 | if (windowEventDescriptor) {
  240 |   Object.defineProperty(window, 'event', windowEventDescriptor);
View compiled
invokeGuardedCallback
H:/ReactJs/Source Codes/react-master/react-master/node_modules/react-dom/cjs/react-dom.development.js:292
  289 | function invokeGuardedCallback(name, func, context, a, b, c, d, e, f) {
  290 |   hasError = false;
  291 |   caughtError = null;
> 292 |   invokeGuardedCallbackImpl$1.apply(reporter, arguments);
  293 | }
  294 | /**
  295 |  * Same as invokeGuardedCallback, but instead of returning an error, it stores
View compiled
flushPassiveEffectsImpl
H:/ReactJs/Source Codes/react-master/react-master/node_modules/react-dom/cjs/react-dom.development.js:22853
  22850 | while (_effect2 !== null) {
  22851 |   {
  22852 |     setCurrentFiber(_effect2);
> 22853 |     invokeGuardedCallback(null, commitPassiveHookEffects, null, _effect2);
        | ^  22854 | 
  22855 |     if (hasCaughtError()) {
  22856 |       if (!(_effect2 !== null)) {
View compiled
unstable_runWithPriority
H:/ReactJs/Source Codes/react-master/react-master/node_modules/scheduler/cjs/scheduler.development.js:653
  650 | currentPriorityLevel = priorityLevel;
  651 | 
  652 | try {
> 653 |   return eventHandler();
      | ^  654 | } finally {
  655 |   currentPriorityLevel = previousPriorityLevel;
  656 | }
View compiled
runWithPriority$1
H:/ReactJs/Source Codes/react-master/react-master/node_modules/react-dom/cjs/react-dom.development.js:11039
  11036 | 
  11037 | function runWithPriority$1(reactPriorityLevel, fn) {
  11038 |   var priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel);
> 11039 |   return Scheduler_runWithPriority(priorityLevel, fn);
  11040 | }
  11041 | function scheduleCallback(reactPriorityLevel, callback, options) {
  11042 |   var priorityLevel = reactPriorityToSchedulerPriority(reactPriorityLevel);
View compiled
flushPassiveEffects
H:/ReactJs/Source Codes/react-master/react-master/node_modules/react-dom/cjs/react-dom.development.js:22820
  22817 |   if (pendingPassiveEffectsRenderPriority !== NoPriority) {
  22818 |     var priorityLevel = pendingPassiveEffectsRenderPriority > NormalPriority ? NormalPriority : pendingPassiveEffectsRenderPriority;
  22819 |     pendingPassiveEffectsRenderPriority = NoPriority;
> 22820 |     return runWithPriority$1(priorityLevel, flushPassiveEffectsImpl);
  22821 |   }
  22822 | }
  22823 | 
View compiled
(anonymous function)
H:/ReactJs/Source Codes/react-master/react-master/node_modules/react-dom/cjs/react-dom.development.js:22699
  22696 | if (!rootDoesHavePassiveEffects) {
  22697 |   rootDoesHavePassiveEffects = true;
  22698 |   scheduleCallback(NormalPriority, function () {
> 22699 |     flushPassiveEffects();
        | ^  22700 |     return null;
  22701 |   });
  22702 | }
View compiled
workLoop
H:/ReactJs/Source Codes/react-master/node_modules/scheduler/cjs/scheduler.development.js:597
  594 | currentPriorityLevel = currentTask.priorityLevel;
  595 | var didUserCallbackTimeout = currentTask.expirationTime <= currentTime;
  596 | markTaskRun(currentTask, currentTime);
> 597 | var continuationCallback = callback(didUserCallbackTimeout);
      | ^  598 | currentTime = exports.unstable_now();
  599 | 
  600 | if (typeof continuationCallback === 'function') {
View compiled
flushWork
H:/ReactJs/Source Codes/react-master/node_modules/scheduler/cjs/scheduler.development.js:552
  549 | try {
  550 |   if (enableProfiling) {
  551 |     try {
> 552 |       return workLoop(hasTimeRemaining, initialTime);
      | ^  553 |     } catch (error) {
  554 |       if (currentTask !== null) {
  555 |         var currentTime = exports.unstable_now();
View compiled
MessagePort.performWorkUntilDeadline
C:/ReactJs/Source Codes/react-master/node_modules/scheduler/cjs/scheduler.development.js:164
  161 | var hasTimeRemaining = true;
  162 | 
  163 | try {
> 164 |   var hasMoreWork = scheduledHostCallback(hasTimeRemaining, currentTime);
      | ^  165 | 
  166 |   if (!hasMoreWork) {
  167 |     isMessageLoopRunning = false;
 

Спасибо

Ответ №1:

Во-первых, вы используете React, поэтому предпочитаете использовать обработчики React, подобные следующим :

 const nextItem = document.querySelector('.next');
nextItem.addEventListener('click', showNextItem);
 

становится :

 <button className="next" onClick={showNextitem}>
  <span>
     <i className="ion-arrow-right-c"></i>
  </span>
</button>
 

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

1. Привет, спасибо. Нужно ли мне использовать состояние?

2. Вам нужно указать, если вам нужно значение оператора во многих функциях и в вашем JSX. Например, вы могли бы перевести свой items в состояние yes

Ответ №2:

вам нужно прочитать несколько статей об обработке событий в react.

useEffect для работы требуется пустой массив в качестве второго параметра componentDidMount .

 useEffect(() => {
    document.addEventListener('keydown', keyPress);
   
    // clean up
    return () => {
    document.removeEventListener('keydown', keyPress);
  };
},[])
 

затем, как сказал Марк Шарпантье, вы добавляете onClick={functionName} в html-элемент.

Причина, по которой вы получаете ошибку, заключается в том, что функциональный компонент не имеет жизненного цикла (в отличие от компонента класса) и выполняется строка за строкой. это означает, что при выполнении этой строки nextItem.addEventListener('click', showNextItem); компонент не вернул ни одного элемента html и он не отображается DOM . его еще не существует, так что это null .

и, как вы можете прочитать из сообщения об ошибке Cannot read property 'addEventListener' of null , он не может найти addEventListener в null

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

1. Привет, спасибо. Нужно ли мне использовать состояние?