简体   繁体   中英

react how to add event listeners to multiple elements at once

To demonstrate my question, I'll compare vanilla javascript and react. In javascript, when I have

<div>
<button class="btn">1</button>
<button class="btn">2</button>
<button class="btn">3</button>
<button class="btn">4</button>
<button class="btn">5</button>
</div>

and I want to add some functionality to all buttons, I can do

const buttons = document.querySelectorAll(".btn");
buttons.forEach(btn=>{
   btn.addEventListener("click",(e)=>{
       //some code here
   })
})

In react, how can I do the same thing, instead of adding "onClick" to every single button? Because imagine if there are 20 buttons like this:

<button className="btn" onClick={()=>{
   //some code here
}}>button</button>

I could still use querySelector like the javascript way, but I heard that is a bad practice in react. So I wonder if there is any other way that can make the code cleaner.

React is perfect for this, because it allows you to reuse components, You could make a component that contains your click handler. then reuse it throughout your application.

 const MyReusableButton = () => { const myClickHandler = () => { console.log("Clicked;"); } return <button onClick = {myClickHandler}>Click Me</button>; } const App = () => { // now I can reuse my button component as many times as I want. return ( <div> <MyReusableButton /> <MyReusableButton /> <MyReusableButton /> <MyReusableButton /> </div> ), } ReactDOM.render(<App />; document.getElementById('root'));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script> <div id="root"></div>

Make a list that describes whatever is unique about your buttons. Map the list into your buttons.

const nums = [0,1,2,3,4,5]
return <div>
    {nums.map(num => 
        <button onClick={() => console.info("clicked" + num)}>
            This is button {num}     
        </button>
    )}
</div>

Instead of attaching a listener to each button you can use event delegation to attach one listener to a container to watch for events as they "bubble up" the DOM from each child element/component.

 function Example() { function handleClick(e) { const { nodeName, textContent } = e.target; if (nodeName === 'BUTTON') { console.log(textContent); } } return ( <div onClick={handleClick}> <button>Click me 1</button> <button>Click me 2</button> <button>Click me 3</button> <button>Click me 4</button> </div> ); }; ReactDOM.render( <Example />, document.getElementById('react') );
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script> <div id="react"></div>

Use a loop to create an array of JSX objects and render them. This is an example from an earlier project I was working on.

  let grid = []
  maze.forEach((row, i) => {
    let renderedRow = []
    row.forEach((block, j) => {
      renderedRow.push(<Block key={size.width * i + j}
        inheritedType={block}
        dimensions={defaultDimensions * scale}
        onAction={() => {
          setBlock(i, j)
          setMazeFuture([])
        }}
        onDoubleClick={() => updateMaze(i, j, "empty")}
        isDown = {isDown}
        setIsDown={setIsDown}
        appendToHistory={appendCurrentMazeToHistory} 
      />)
    })
    grid.push(<Row key={i} columns={renderedRow} rowHeight={defaultDimensions * scale}/>)
  })

return (
   {grid}
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM