How to setState on click event, only once within a loop? - javascript

I have a function where I am looping through a list of labels.
I have a onClick event where I am calling a function.
This function sets the state for clicked to that of the id of the clicked item in the loop. The function also console.log's the state.
It's logging the state of clicked 8 times. There are current 4 items in my loop.
How can I make it so that I can set the state to clicked every time the user clicks on an item in the list?
Here is my loop:
{
filteredArray.map(link => {
return (
<div
key={link.id}
role="button"
style={{paddingBottom: 20}}
onClick={this.changeView(link.id)}
onKeyPress={this.changeView(link.id)}
tabIndex={0}
>
<Paragraph size="large">
<a className='heading__dropdown__link'
{link.label}
</a>
</Paragraph>
</div>
)
})
}
Here is my function changeView:
changeView(id) {
const { clicked } = this.state
console.log(clicked)
return (
() => this.setState({clicked: id})
)
}

Your calling the function for every element, set your function like so:
changeView = id => ev => this.setState({clicked: id});

remove onPress and add arrow function in onClick like this
onClick={()=>this.changeView(link.id)}
hope this will help

Related

onClick handler in React is triggered by adjacent element , not by element which it was meant to trigger

const ProductScreen = () => {
const [qty, setQty] = useState(0);
const handleAddtoCart = () => {
console.log(qty);
};
return (
<div className="productScreen">
{product.countInStock > 0 && (
<div className="productScreen__details__qty">
<span>Qty : </span>
<select
id="qty"
name="qty"
value={qty}
onChange={(e) => setQty(e.target.value)}
>
{[...Array(product.countInStock).keys()].map((x) => (
<option key={x + 1} value={x + 1}>
{x + 1}
</option>
))}
</select>
</div>
)}
{product.countInStock > 0 ? (
<div className="productScreen__details__price__details__cart">
<button
className="productScreen__details__price__details__toCart"
onClick={handleAddtoCart()}
>
Add to Cart
</button>
</div>
</div>
</div>
);
};
Here handleAddtoCart gets triggered when selecting options but doesnt trigger when button is pressed(handleAddtoCart is added to button), when I change handleAddtoCart() to handleAddtoCart in onClick attribute of button it works properly.
Why when handleAddtoCart() is given as onclick attribute it is getting triggered by adjacent select option and is not getting triggered when button is pressed
You need to make a callback to that function, because every render of the component, will literally execute handleAddtoCart() and not as you expect it to happen only of the onClick trigger.
as react's Offical documents explained:
To save typing and avoid the confusing behavior of this, we will use the arrow function syntax for event handlers here and further below:
class Square extends React.Component {
render() {
return (
<button className="square" onClick={() => console.log('click')}>
{this.props.value}
</button>
);
}
}
Notice how with onClick={() => console.log('click')}, we’re passing a function as the onClick prop. React will only call this function after a click. Forgetting () => and writing onClick={console.log('click')} is a common mistake, and would fire every time the component re-renders.
for more details:
https://reactjs.org/tutorial/tutorial.html
Change
onClick={handleAddtoCart()}
by
onClick={handleAddtoCart}
Also try with :
onChange={(e) => setQty(e.currentTarget.value)}
instead of :
onChange={(e) => setQty(e.target.value)}
The currentTarget read-only property of the Event interface identifies
the current target for the event, as the event traverses the DOM. It
always refers to the element to which the event handler has been
attached, as opposed to Event.target, which identifies the element on
which the event occurred and which may be its descendant.
https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget

Ag-Grid Prevent onRowClicked event when clicking icon inside cell

I have a cell renderer that returns the name property and objects on a row:
const nameRenderer = ({ value, data }) => {
const { id: queueId } = data;
return (
<Box>
<div className="row-hidden-menu">
<IconButton
icon="menu"
onClick={({ event }) => {
event.preventDefault();
event.stopPropagation();
onMenuClick();
}}
/>
</div>
</Box>
);
};
The issue I have is that I have an onRowClick function but I don't want that function to be called when I click the icon from the nameRenderer. Right now when the menu opens, the onRowClicked event navigates to a new page.
See this answer for more in-depth explanation, but the gist is that the event that you receive from the onClick callback is React's synthetic event which is a wrapper of the native event. Calling stopPropagation() from a synthetic event will not stop the real event from bubbling up and it is a quirk of the React framework for a long time.
Solution: attach your onClick event handler to the real DOM element instead.
function ButtonCellRenderer() {
return (
<button
ref={(ref) => {
if (!ref) return;
ref.onclick = (e) => {
console.log("native event handler");
e.stopPropagation(); // this works
// put your logic here instead because e.stopPropagation() will
// stop React's synthetic event
};
}}
onClick={(e) => {
e.stopPropagation(); // this doesn't work
}}
>
Click me
</button>
);
}
Live Demo

deleting an item from array in React with unique id

I am a newbie and trying to delete an item from array by clicking a button.
However, I could not retrieve the id I want.
All I could get from e.target was the "input" itself, not the whole item, let alone the id.
//some other stuff
deleteDrink = (event) => {
console.log(event.target)
}
return(
//blahblahblah[enter image description here][1]
orders.map((order, i) => (
<Order
key={orders[i].id}
drink={orders[i].drink}
price={orders[i].price}
quantities={orders[i].number}
note={orders[i].note}
deleteDrink={this.deleteDrink}
/>
) ```
When I clicked the button, all I can get is:
<input class="delete-button br4 w-10 grow" type="button" value="Delete"></input>
what should I do to retrieve the id?
[1]: https://i.stack.imgur.com/KM7Ng.jpg
Instead of setting the handler to this.deleteDrink, set a handler which calls deleteDrink with the ID (or index) of the element to be deleted:
deleteDrink={() => { this.deleteDrink(order.id); }}
deleteDrink = (id) => {
console.log('deleting', id)
}
To delete the particular order when deleteDrink is called, perhaps you'd want something like this:
deleteDrink={() => { this.deleteDrink(i); }}
// Example if you're using hooks:
deleteDrink = (i) => {
setOrders([
...orders.slice(0, i),
...orders.slice(i + 1)
]);
}

React - event.target returns the innerText of the previously clicked element instead of the currently clicked element

I created a drop down menu that returns a selected option through an event handler when the option is clicked.
When I click on the option, I target the innerText of that option via event. It looks like this: event.target.innerText. The selected targets value is then used to fill in an 'input' to show the users selected value. Exactly how you expect a <select> input to work. The targets value is also used for filtering listed components, but that is not what I am worried about here.
When the drop down menu component loads, inside of a componentDidMount() method, the state is updated with a default value so that the drop down menus load with the first option pre-populated (this is so that they are not empty before a user selects an option).
When I click on an option to make a selection, the returned event.target.innerText is of the previous selection. So if option 1 was the default value when the component mounts, and then I select option 2 and console.log the result, the value would be option 1. If I then select another option, option 3, the returned console.log() would be option 2. It's one behind.
In this .gif, you can see that when componentDidMount() fires, it console.log()s the default values of the drop down menu. But when I make a selection, you'll notice the console.log() is only returning the event.target.innerText of the previously selected option.
Here is the component:
class DropDownSelect extends Component {
constructor(props) {
const { inputOptions } = props;
const { option1 } = inputOptions;
super(props);
this.state = {
showOptions: false,
selectionMade: option1
};
}
setShowOptions = () => {
const { showOptions } = this.state;
this.setState(prevState => ({ showOptions: !prevState.showOptions }));
};
setSelectionMade = event => {
const { target } = event;
event.stopPropagation();
this.setShowOptions();
this.setState({ selectionMade: target.innerText });
console.log(this.state.selectionMade);
};
setDefaultSelectionOnLoad = () => {
const { inputOptions } = this.props;
this.setState({ selectionMade: inputOptions.option1 });
};
componentDidMount() {
this.setDefaultSelectionOnLoad();
console.log(this.state.selectionMade);
}
render() {
const { showOptions, selectionMade } = this.state;
const { inputOptions } = this.props;
const inputOptionsArray = Object.keys(inputOptions);
return (
<DropDownSelectMenu>
<DropDownSelectPlaceholder onClick={this.setShowOptions}>
<p>{selectionMade}</p>
<i>
<FontAwesomeIcon icon={faCaretDown} />
</i>
</DropDownSelectPlaceholder>
{showOptions ? (
<DropDownSelectOptions>
{inputOptionsArray.map((key, index) => {
return (
<DropDownOption
onClick={event => {
this.setSelectionMade(event);
}}
key={index}
>
{inputOptions[key]}
</DropDownOption>
);
})}
</DropDownSelectOptions>
) : null}
</DropDownSelectMenu>
);
}
}
The DropDownOption styled component is where the function that updates the selection in the state is added as an onClick handler. Since this component is a child, and you need to click the parent component to open the DropDownOption component, I thought that maybe the event handler was bubbling up and grabbing the event.target value from the parent, so I added event.stopPropagation() to the event handler function setSelectionMade(). This didn't do anything for me.
Your code works fine, only this debugging method fails ;)
This is of the most common errors in react - expecting state update immediatelly just after setState call.
Read docs, please. Value can be read in setState callback.
You can simply console.log(selectionMade) in render (before return () to get current value.

React : test a function which is passed as a props and is triggered by the parent

I'm trying to trigger a click event for my test. As this :
describe('Button', function() {
test('is clicked when player two is pending', (props ={}) => {
const mockRandomAdv = sinon.spy();
const tree = shallow(
<FightButton
button="Random adversary"
isPlayerTwoPending={true}
isPlayerOnePending={false}
onClick={mockRandomAdv}
/>
);
tree.find('Button').simulate('click');
//expect(mockRandomAdv.calledOnce).toEqual(true);
console.log(tree.props().children.onClick)
//.not.toBe('fight-button random');
});
});
The first expectation return false so the click is not triggered.
When i console.log() the click event it returns undefined.
Here is my child (which is not the last last child).
<Button
onClick={ () => { this.props.randomAdversary }}
class="fight-button random"
button="Random adversary"
/>
And here is the parent that is calling the child and who describe the method :
class Board extends Component {
constructor(props) {
..my constructor
}
randomAdversary() {
...my function
}
return (<div> <FightButton
isPlayerTwoPending={this.state.adversaryPending}
isPlayerOnePending={this.state.characterPending}
isPlayerOneTheWinner={this.state.heroWin}
isFighting={this.state.fighting}
randomAdversary={this.randomAdversary}
fight={this.fight(100)}
playAgain={this.playAgain()}
/>
</div>
)
}
When i click, the class of my button must change. But the same when i console.log the class, it has no changed. Is something wrong with my test ?
Looking at the button, I don't see calling the function correctly. I'ts actually doing nothing, you need to execute the function like this:
<Button
onClick={ () => { this.props.randomAdversary() }} // Add the `()`
class="fight-button random"
button="Random adversary"
/>

Categories