I wrote a React component below and observed weird behavior. All of Button-B,C,D works as expected, executing the function specified in the onClick, but only the Button-A do not. If I click Button-A, it redirects me to the root path without any output to the console. Could someone help me to understand what is happening here and how I can make Button-A work, meaning assign the click event to a function I defined in the component? I assume this relates to the React event delegation but could not identify the root cause and how to solve. Thanks in advance.
import React, { useState, useEffect } from 'react'
import uuid from "react-uuid"
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faSquarePlus } from '@fortawesome/free-solid-svg-icons'
import "./Create.css"
function CreateOld() {
const [tickers, setTickers] = useState([{id: uuid(), ticker: "", ratio: ""}]);
const addTicker = () => {
console.log("add ticker pressed")
const newTicker = {
id: uuid(),
ticker: "",
ratio: "",
}
setTickers([...tickers, newTicker])
console.log(tickers);
}
const onUpdateTicker = (updatedTicker) => {
const updatedTickersArray = tickers.map((ticker) => {
if (ticker.id === updatedTicker.id){
return updatedTicker;
} else {
return ticker;
}
});
setTickers(updatedTickersArray);
}
const onEditTicker = (ticker, key, value) => {
onUpdateTicker({
...ticker,
[key]: value,
})
};
const clickHandlerA = () => {
console.log('Clicked Button-A');
};
const clickHandlerB = () => {
console.log('Clicked Button-B');
};
const clickHandlerC = () => {
console.log('Clicked Button-C');
};
const clickHandlerD = () => {
console.log('Clicked Button-D');
};
return (
<div>
<div>
<div>
<button type="button" className='createButton' id="button-A" onClick={clickHandlerA}>
Button-A
</button>
</div>
<div>
{errorMessage && <div className='error-message'>{errorMessage}</div>}
</div>
<div>
{tickers.map((ticker,index)=>(
<div className="tickerContainer" key={ticker.id} id={ticker.id}>
<div className="inputPortfolio">
<div>Ticker</div>
<input type="text" placeholder='Ticker' value={ticker.ticker} onChange={(e) => onEditTicker(ticker, "ticker", e.target.value)}/>
</div>
<div className="inputPortfolio">
<div>Unit/Unit Ratio</div>
<input type="text" placeholder='Unit/Unit Ratio' value={ticker.ratio} onChange={(e) => onEditTicker(ticker, "ratio", e.target.value)}/>
</div>
</div>
))}
</div>
<div className="addTickerButton">
<button type="button" className='createTickerButton' id="addTickerButton" onClick={addTicker}>
<FontAwesomeIcon icon={faSquarePlus} />Button-B
</button>
</div>
<div>
<button type="button" className='createButton' id="button-B" onClick={clickHandlerC}>
Button-C
</button>
</div>
</div>
<div className="createPortfolioButton">
<button type="button" className='createButton' id="createPortfolioButton" onClick={clickHandlerD}>
Button-D
</button>
</div>
</div>
)
}
export default CreateOld
I expected to execute clickHandlerA when I clicked Button-A. Also, I tried to add e.preventDefault() and e.stopPropagation() but none of them did not solve the problem.
Parent Component App.jsx
import Nabvar from './components/Navbar'
import Home from './components/Home'
import Portfolio from './components/Portfolio'
import NewPortfolio from './components/NewPortfolio'
import { BrowserRouter as Router, Routes, Route } from "react-router-dom"
function App() {
return (
<div>
<Router>
<Nabvar />
<Routes>
<Route path="/" element={<Home/>}></Route>
<Route path="/new" element={<NewPortfolio/>}></Route>
<Route path="/portfolio/:portfolio_id" element={<Portfolio/>}></Route>
</Routes>
</Router>
</div>
)
}
export default App
It's probably because of (ancient) HTML5 semantics around forms. I'm guessing some parent component wraps all of this in a
<form>. The first button inside a form is assigned as the submit button by default in HTML5. When you submit a form, theonSubmitis called on that<form>. If no such handler is present, it does the browser default which is toPOSTthe form contents to the current URL. It'll also do that if there is a handler but there's noe.preventDefault().Your code doesn't show the parent, but you should add an
onSubmitprop to theformif there isn't one and then calle.preventDefault()in that handler. If there already is one, add thee.preventDefault()to the top of it.