skip to Main Content

The title might seem ambiguous, so I’m going to try and explain it as best as I can.

I’m running a React project from VSC on localhost (with ‘npm start’). The project is really simple now, it only has 2 text inputs and a couple of buttons to make things. The problem is, when I first launch the command to initialize the project on localhost it runs ok but my buttons are not working. I have to change something on VSC (a simple space is enough) and save the project in order for it to recompile on the go and start working. After recompiling it works fine with every Event Listener call, and can call them as many times as I want. I leave my code right here:

import logo from './logo.svg';
import './App.css';

function App() {
  return (

    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          {/* Edit <code>src/App.js</code> and save to reload.  */}
          Search Engine
        </p>
        <p>
          <table>
            <tr>
              <td>
                Enter the token
              </td>
              <td>
                <input type="text" id="inputtext" placeholder='Token' />
              </td>
            </tr>
            <tr>
              <td></td>
              <td>
                <button type="button" id="add">Add</button>
                <button type="button" id="display">Display</button>
                <button type="button" id="remove">Remove</button>
                <button type="button" id="">Search!</button>
              </td>
            </tr>
            <tr>{"----------------------------"}</tr>
            <tr>
              <td>
                Web link
              </td>
              <td>
                <input type="text" id="inputtext" placeholder='Token' />
              </td>
            </tr>
            <tr>
              <td></td>
              <td>
                <button type="button" id="">Search!</button>
              </td>
            </tr>

          </table>
        </p>
      </header>
    </div>
  );
}
let addButton = document.querySelector('#add');
let displayButton = document.querySelector('#display');
let removeButton = document.querySelector('#remove');
let records = [];

addButton?.addEventListener('click', addRecord);
displayButton?.addEventListener('click', displayAll);
removeButton?.addEventListener('click', removeRecord);

function addRecord() {
  let record = document.querySelector('#inputtext').value.trim();
  if (!record) {
    alert('No value inserted');
    return;
  }
  if (records.includes(record)) {
    alert('Duplicated token');
    return;
  }
  records.push(record);
  document.querySelector('#inputtext').value = '';
}

function displayAll() {
  if (records.length === 0) {
    alert("[Empty list]")
    return;
  }
  alert(records.sort());
}

function removeRecord() {
  let record = document.querySelector('#inputtext').value.trim();
  if (!record) {
    alert('No value inserted');
    return;
  }
  if (records.length === 0) {
    alert("[Empty list]")
    return;
  }
  if (!records.includes(record)) {
    alert("Non existing value")
    return;
  }
  const index = records.indexOf(record);
  records.splice(index, 1);
  document.querySelector('#inputtext').value = '';
  alert("Succesfully removed " + record);
}

export default App;

I think the problems comes with the Event Listeners right here, but I might be wrong

addButton?.addEventListener('click', addRecord);
displayButton?.addEventListener('click', displayAll);
removeButton?.addEventListener('click', removeRecord);

If anyone knows anything about this, please respond. Thanks in advance.

I have tried reordering the code and the Event Listener calls but it has not worked for me.

3

Answers


  1. The issue you’re facing seems to be related to the event listeners not being properly attached to the buttons when the initial render occurs. The event listeners are being set up outside of the React component, which means they are executed before the buttons are rendered and may not find the buttons to attach the listeners to.

    To fix this issue, you should move the event listener setup inside the component’s body and use React’s event handling instead of directly accessing the DOM. Here’s an updated version of your code with the necessary modifications:

    import logo from './logo.svg';
    import './App.css';
    import { useState } from 'react';
    
    function App() {
      const [inputValue, setInputValue] = useState('');
      const [records, setRecords] = useState([]);
    
      const handleAddRecord = () => {
        const record = inputValue.trim();
        if (!record) {
          alert('No value inserted');
          return;
        }
        if (records.includes(record)) {
          alert('Duplicated token');
          return;
        }
        setRecords([...records, record]);
        setInputValue('');
      };
    
      const handleDisplayAll = () => {
        if (records.length === 0) {
          alert('[Empty list]');
          return;
        }
        alert(records.sort());
      };
    
      const handleRemoveRecord = () => {
        const record = inputValue.trim();
        if (!record) {
          alert('No value inserted');
          return;
        }
        if (records.length === 0) {
          alert('[Empty list]');
          return;
        }
        if (!records.includes(record)) {
          alert('Non-existing value');
          return;
        }
        const updatedRecords = records.filter((item) => item !== record);
        setRecords(updatedRecords);
        setInputValue('');
        alert('Successfully removed ' + record);
      };
    
      return (
        <div className="App">
          <header className="App-header">
            <img src={logo} className="App-logo" alt="logo" />
            <p>Search Engine</p>
            <p>
              <table>
                <tbody>
                  <tr>
                    <td>Enter the token</td>
                    <td>
                      <input
                        type="text"
                        value={inputValue}
                        onChange={(e) => setInputValue(e.target.value)}
                        placeholder="Token"
                      />
                    </td>
                  </tr>
                  <tr>
                    <td></td>
                    <td>
                      <button type="button" onClick={handleAddRecord}>
                        Add
                      </button>
                      <button type="button" onClick={handleDisplayAll}>
                        Display
                      </button>
                      <button type="button" onClick={handleRemoveRecord}>
                        Remove
                      </button>
                      <button type="button">Search!</button>
                    </td>
                  </tr>
                  <tr>----------------------------</tr>
                  <tr>
                    <td>Web link</td>
                    <td>
                      <input type="text" placeholder="Token" />
                    </td>
                  </tr>
                  <tr>
                    <td></td>
                    <td>
                      <button type="button">Search!</button>
                    </td>
                  </tr>
                </tbody>
              </table>
            </p>
          </header>
        </div>
      );
    }
    
    export default App;
    

    In this modified version, the event listeners are now attached to the buttons using the onClick prop within the JSX code. The corresponding event handler functions are defined within the component and use the state hooks (useState) to update the records and inputValue states.

    With these changes, the event listeners will be properly set up within the React component’s lifecycle, and the buttons should work as expected without requiring a manual recompilation.

    Login or Signup to reply.
  2. First of all, you declared your functions outside of your React component which is App in your code.
    React can’t control over outside of React component.

    You can make your own functions its outside but that functions should be pure functions. When you need a side effect, you want to put in the component.

    so rewrite some of your code in a React way. You can get the concept from this. And never forget check official document! > https://react.dev/

    function App() {
      const addRef = useRef(null);
      const inputRef = useRef(null);
      const [records, setRecords] = useState([]);
    
      const addRecord = () => {
        const inputValue = inputRef.current?.value;
    
        if (!inputValue) {
          alert("No value inserted");
          return;
        }
    
        if (records.includes(inputValue)) {
          alert("Duplicated token");
          return;
        }
    
        setRecords((prevRecord) => {
          const newRecord = [...prevRecord];
          newRecord.push(inputValue);
    
          return newRecord;
        });
    
        inputRef.current.value = "";
      };
    
      return (
        <div className="App">
          <header className="App-header">
            <p>
              {/* Edit <code>src/App.js</code> and save to reload.  */}
              Search Engine
            </p>
            <p>
              <table>
                <tr>
                  <td>Enter the token</td>
                  <td>
                    <input
                      ref={inputRef}
                      type="text"
                      id="inputtext"
                      placeholder="Token"
                    />
                  </td>
                </tr>
                <tr>
                  <td></td>
                  <td>
                    <button ref={addRef} type="button" id="add" onClick={addRecord}>
                      Add
                    </button>
                    <button type="button" id="display">
                      Display
                    </button>
                    <button type="button" id="remove">
                      Remove
                    </button>
                    <button type="button" id="">
                      Search!
                    </button>
                  </td>
                </tr>
                <tr>{"----------------------------"}</tr>
                <tr>
                  <td>Web link</td>
                  <td>
                    <input type="text" id="inputtext" placeholder="Token" />
                  </td>
                </tr>
                <tr>
                  <td></td>
                  <td>
                    <button type="button" id="">
                      Search!
                    </button>
                  </td>
                </tr>
              </table>
            </p>
          </header>
          <ul>
            {records.map((record, idx) => {
              return <li key={idx}>{record}</li>;
            })}
          </ul>
        </div>
      );
    }
    
    Login or Signup to reply.
  3. First of all you are not using the React here properly. You are just using the jsx where you can write the html and javascript in a single file.

    Now why it may be happening that when you are loading then the event listeners are not invoking is because the react renders the component asynchronously so on the first load the elements are not captured in the javasript and that’s why no event listeners are registered.

    So instead of doing this way use the useState or useRef and use this functions inside the components and let the React handle the rendering of the components and registeration of the event listeners(use onClick, onChange, etc.) itself and leverage the power of react.

    Please let me know if these can be of any help and if

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search