how to prevent on click to work infinite times? - javascript

once i click these buttons the function provided to them by onClick event does an infinite loop and the page freezes
is there any possible way to prevent it?
<section>
<button
onClick={() => {
this.setState({ category: "image" });
}}
>
Image
</button>
<Button>Figure</Button>
<Button>Image</Button>
</section>
<section className="hello">
{this.state.store &&
this.state.store.map((st) => {
if (st[0].exist && st[0].category == this.state.category) {
return (
<div className="eachC">
<Card
category={st[0].category}
image={st[0].image}
price={st[0].price}
name={st[0].name}
/>
<section>
<Button onClick={this.setState({ save: 1 }, () => {})}>
Delete
</Button>
<Button onClick={this.setState({ save: 1 }, () => {})}>
Update
</Button>
</section>
</div>
);
}
})}
</section>

It's kind of hard to tell exactly why an infinite loop is caused without seeing what other logic you have prior to the render, and also without knowing which buttons are causing you the issue, because you currently have multiple buttons that do different things.
However I can see right now that you are not passing a function to the onClick event for the Update and Delete button, but instead you are making a function call, which will be called when the component is rendered instead of when clicking. So it is bound to not work properly.
You need to wrap those in a function like you do for your Image button, and you also don't need the empty callback you have added. So I would change that to something like this:
<Button onClick={() => this.setState({ save: 1 })}>
Delete
</Button>
<Button onClick={() => this.setState({ save: 1 })}>
Update
</Button>
However, I am not sure if this is what is causing your infinite loop as you haven't included any more logic in your question!

Related

How to buy a building and update individual sections of one state using react

Im making an idle clicker game for a project. you buy a building from a list in state that i map and display. if you click the buy button you get one.
im really close i can feel it. I want to set up my buildings state with how many i own and the effect they each have. How can i update my state so that only the one building i click buy from is added.
i know it has something to do with ...state, 'then add new stuff' but i cant get it to work. so i have taken my code to a simple working version. you can click the buy button and get all the buiilding details. What next. I get the building list from a json file i made.
const [buildingsList, setBuildingsList] = useState([])
const [buildingsOwned, setBuildingsOwned] = useState({
buildingOne: 0,
buildOneBonus: 100,
buildingTwo: 0,
buildingTwoBonus: 1000,
buildingThree: 0,
buildingThreeBonus: 10000
})
const buyBuilding = (building) => {
console.log('building', building);
}
<LeftMenu buildingsList={buildingsList} buyBuilding={buyBuilding} />
function LeftMenu({ buildingsList, buyBuilding }) {
return (
<section className="left-menu">
<h2>Buildings</h2>
{buildingsList.map((building, index) => {
return (
<div className="item" key={index}>
<img src={building.url} alt="merchant building" />
<div>{building.name}</div>
<div>£{building.cost}</div>
<div>Owned: 1</div>
<button onClick={() => buyBuilding(building)}>Buy</button>
</div>
);
})}
</section>
);
}
export default LeftMenu;
If I understand correctly, for example buildingOne: 0 and you want to update it as buildingOne: 1
setBuildingsOwned(prevState => ({...prevState, buildingOne: prevState.buildingOne+1}))

React Conditional Rendering Child

I'm new to React and trying to understand using props with conditional rendering. I have a component called Intro.js inside my app.js.
My goal is to click a button on a form in Intro.js and remove Intro from app.js I've been able to accomplish this with a button in app.js but not within Intro.js. How would I get this to work within the child component Intro.js
const [introSection, setIntroSection] = useState(false)
{
introSection ? <Intro /> : true
}
<Button onClick={() => setIntro(false)}> Remove Intro Section</Button>
Firstly, your state update is also not aligned with the actual function. It should be setIntroSection instead of setIntro
<Button onClick={() => setIntroSection(false)}> Remove Intro Section</Button>
You're almost there with your logic. You just need to modify your logic like below
{
introSection ? <Intro /> : null
}
<Button onClick={() => setIntroSection(false)}> Remove Intro Section</Button>
But this is not a good way when we have a very complex structure in the true path, so I personally prefer this way
{introSection && <Intro />} //when it's false, nothing is rendered
<Button onClick={() => setIntroSection(false)}> Remove Intro Section</Button>
If you want to do it inside Intro, you can pass a prop
<Intro isHidden={true} />
And in Intro, you can have this logic
const Intro = ({ isHidden }) => {
if(isHidden) {
return null
}
//true path to render your own component
return <div></div>
}
You should pass your setIntro/setIntroSection (it depends how you used it) function to Intro component as a prop, so then you will be able to access and use that state function. I hope this helps.
Use setIntroSection, not setIntro.
A whole bunch of code will be helpful to answer.

Why my onclick getting called on each render in react js?

I am making a react application and on every render my variable gets changed even if the state change logic is inside a onClick function.
Here's my code:
constructor() {
super();
this.state = {
options: [],
suboptions: [],
saveflag:false
};
}
<div>
{
console.log(this.state.saveflag),
saveflag?<></>:
<button
type="button"
className="btn"
onClick={() => this.props.data.handleApiGrants(apis),this.setState({saveflag:true})}
>
Save
</button>}
</div>
</div>
Above I have set the flag saveflag to false initially and I want to change it on click of the save button but its getting changed on every render.
Can someone help?
you have a problem with syntax, now it will work:
onClick={() => {
this.props.data.handleApiGrants(apis);
this.setState({ saveflag: true });
}}
preventDefault should help:
onClick={e => {
e.preventDefault();
this.props.data.handleApiGrants(apis);
this.setState({saveflag:true});
}}

onClick() works on the first click only - React

I am trying to make onClick() function work for every button (its the same result), but as of now onClick() works only once.
If I click on a button again (the same or different) the pop up doesn't work anymore.
Could you please help? I cannot figure out how to fix it.
function Challange() {
const [isPopped, setPop] = useState(false);
const pop = () => {
setPop(true);
};
return (
<>
{isPopped && <Dialog2 />}
<div className="challanges">
<h1 className="newchallenge">Choose New Challange</h1>
<button className="challangeBtn" onClick={pop}>
Eat Vegetarian (31days)
</button>
<button className="challangeBtn" onClick={pop}>
Take the bike to work (14days)
</button>
<button className="challangeBtn" onClick={pop}>
Recycle your plastic bottles (31days)
</button>
<button className="challangeBtn" onClick={pop}>
Use public transport to commute (31days)
</button>
<button className="challangeBtn" onClick={pop}>
Don't fly an airplane (365days)
</button>
</div>
</>
);
}
export default Challange;
Your pop function code only sets the state to true, so it will never be false again. You may change it like this.
const pop = () => {
setPop(!isPopped);
};
in your case setPop can take boolean value OR method that returns boolean.
Best practices for handle toggling in React looks like:
const pop = () => {
setPop(currentValue => !currentValue);
};
Also, use useCallback hook to manage events like click and avoid re-initialization of your method on each render:
const pop = useCallback(() => {
setPop(currentValue => !currentValue);
}, []);

React: state not updating on first click

I am working on a shopping cart sample.
On each click, I am adding an object of the project to the Cart array.
When I click the add cart button the first time, it doesn't update the Cart, but it updates on the second time.
Although, when I click the viewCart button in the render's return statement, it shows the accurate number of items in the cart.
See my code below:
I need to be able to see the accurate number of items in the cart without clicking the viewCart button. The products come from a local JSON file, so I don't think there is any problem with the loading of the JSON file.
constructor (props) {
super(props);
this.state = {
Cart: []
};
this.addItem = this.addItem.bind(this);
}
addItem(productKey) {
this.setState({ Cart: [...this.state.Cart, ProductsJSON[productKey]]})
console.log(this.state.Cart);
}
viewCart() {
console.log(this.state.Cart);
}
render() {
const AllProducts = ProductsJSON;
var Products = AllProducts.map((item) => {
return (
<div className="col-4" key={item.key} >
<a onClick={() => this.addItem(item.key)} className="btn btn-primary btn-sm">Add to Cart</a>
</div>
)
})
return (
<div className="container">
<div className="row">
{Products}
<a onClick={() => this.viewCart()} className="btn btn-primary btn-sm">viewCart</a>
</div>
</div>
)
}
Just because you don't see it in console.log doesn't mean it will not render correctly, the problem here is that setState is asynchronous, thus you will not see it if you console.log it right away (console.log will execute before state is updated), but if you still want to do log your cart, you can do:
this.setState(
{ Cart: [...this.state.Cart, ProductsJSON[productKey]] },
() => console.log(this.state.Cart)
)
setState accepts a function as a callback once the state has been updated.
Arber's solution makes sense but when I tried it, it produced a console warning saying:
State updates from the useState() and useReducer() Hooks don't support
the second callback argument. To execute a side effect after
rendering, declare it in the component body with useEffect().

Categories

Resources