Hi so i got my react function with a state that i use to know which componont should be rendered at a given time; here is my main App Function (i only include the function not the rest of class since it is not relevent)
My app function
function App(){
const [menuState, setMenuState] = useState('journal');
return(
<>
<button onClick={setMenuState('journal')}>JOUNRAL</button>
<button onClick={setMenuState('stats')}>STATS</button>
<MenuHandler menu={menuState}/>
</>
);
}
My MenuHandler function
function MenuHandler(props) {
const menu = props.menu;
if(menu==="journal")
return (<Journal />);
if(menu==="stats")
return (<Stats />);
return (<Journal />);
}
When i do this i get an infinite loop and i can't figure out why.
The problem is that you are calling setMenuState on each render, therefore the infinite loop. You are not assigning it to the onClick handler, pass an arrow function like this to solve it:
<button onClick={() => setMenuState('journal')}>JOUNRAL</button>
<button onClick={() => setMenuState('stats')}>STATS</button>
Related
I pass 2 values to a child component:
List of objects to display
delete function.
I use a .map() function to display my list of objects(like in the example given in react tutorial page), but the button in that component fires the onClick function, on render(it should not fire on render time). My code looks like this:
module.exports = React.createClass({
render: function(){
var taskNodes = this.props.todoTasks.map(function(todo){
return (
<div>
{todo.task}
<button type="submit" onClick={this.props.removeTaskFunction(todo)}>Submit</button>
</div>
);
}, this);
return (
<div className="todo-task-list">
{taskNodes}
</div>
);
}
});
My question is: why does onClick function fire on render and how to make it not to?
Because you are calling that function instead of passing the function to onClick, change that line to this:
<button type="submit" onClick={() => { this.props.removeTaskFunction(todo) }}>Submit</button>
=> called Arrow Function, which was introduced in ES6, and will be supported on React 0.13.3 or upper.
Instead of calling the function, bind the value to the function:
this.props.removeTaskFunction.bind(this, todo)
MDN ref: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind
The Problem lies in how you pass your function
At the moment you are not passing the function but Calling it instead:
<Button onClick={yourFunction()} />
You can Fix this in two ways:
<Button onClick={() => yourFunction(params)} />
Or if you dont have any params:
<Button onClick={yourFunction} />
The value for your onClick attribute should be a function, not a function call.
<button type="submit" onClick={function(){removeTaskFunction(todo)}}>Submit</button>
you need to use an arrow function with onClick in order to prevent immediately invoke.
so if your button looks like this :
<button onClick={yourfunctionname()} />
it must be like this :
<button onClick={() => yourfunctionname(params)} />
JSX is used with ReactJS as it is very similar to HTML and it gives programmers feel of using HTML whereas it ultimately transpiles to a javascript file.
Writing a for-loop and specifying function as
{this.props.removeTaskFunction(todo)} will execute the functions
whenever the loop is triggered .
To stop this behaviour we need to return the function to onClick.
The fat arrow function has a hidden return statement along with the bind
property. Thus it returns the function to OnClick as Javascript can
return functions too !!!!!
Use -
onClick={() => { this.props.removeTaskFunction(todo) }}
which means-
var onClick = function() {
return this.props.removeTaskFunction(todo);
}.bind(this);
For those not using arrow functions but something simpler ... I encountered this when adding parentheses after my signOut function ...
replace this <a onClick={props.signOut()}>Log Out</a>
with this <a onClick={props.signOut}>Log Out</a> ... ! 😆
JSX will evaluate JavaScript expressions in curly braces
In this case, this.props.removeTaskFunction(todo) is invoked and the return value is assigned to onClick
What you have to provide for onClick is a function. To do this, you can wrap the value in an anonymous function.
export const samepleComponent = ({todoTasks, removeTaskFunction}) => {
const taskNodes = todoTasks.map(todo => (
<div>
{todo.task}
<button type="submit" onClick={() => removeTaskFunction(todo)}>Submit</button>
</div>
);
return (
<div className="todo-task-list">
{taskNodes}
</div>
);
}
});
I had similar issue, my code was:
function RadioInput(props) {
return (
<div className="form-check form-check-inline">
<input className="form-check-input" type="radio" name="inlineRadioOptions" id={props.id} onClick={props.onClick} value={props.label}></input>
<label className="form-check-label" htmlFor={props.id}>{props.label}</label>
</div>
);
}
class ScheduleType extends React.Component
{
renderRadioInput(id,label)
{
id = "inlineRadio"+id;
return(
<RadioInput
id = {id}
label = {label}
onClick = {this.props.onClick}
/>
);
}
Where it should be
onClick = {() => this.props.onClick()}
in RenderRadioInput
It fixed the issue for me.
It is possible to achieve this even in more readable way than:
<button onClick={() => somethingHere(param)}/>
const Comp = () => {
const [triggered, setTriggered] = useState(false);
const handleClick = (valueToSet) => () => {
setTriggered(valueToSet);
};
return (
<div>
<button onClick={handleClick(true)}>Trigger</button>
<div>{String(triggered)}</div>
</div>
);
};
That way it won't fire the state setter and won't cause too many re-renders compared to <button onClick={setTriggered(true)}/>
which is okay if you don't have any params to pass to the function.
That's because you are calling the function directly instead of passing the function to onClick
If you have passed down onClick={onClickHandler()} then, the function onClickHandler() will be executed during the time of rendering too, the () instructs to execute the function as soon as it is rendered , which is not desired here , instead we use onClick={onClickHandler} , this will execute the onClickHandler only when the specified event occurs. But if we want to pass down a argument along with the function then we can make use of ES6 arrow function.
For your Case :
<button type="submit" onClick={() => this.props.removeTaskFunction(todo)}>Submit</button>
Bit late here but here is the simple answer.
direct approach will trigger by itself due to JS DOM rendering
onClick={this.props.removeTaskFunction(todo)}
anonymous arrow function approach. it will trigger on click
onClick={()=>this.props.removeTaskFunction(todo)}
You are not passing the function as an argument you are calling it directly that why it launches on the render.
HOW TO FIX IT
there are two ways:
First
<Button onClick={() => {
this.props.removeTaskFunction(todo);
}
}>click</Button>
OR
Just bind it
this.props.removeTaskFunction.bind(this,todo);
This happens when i try to conditonally render using a button, what should i do?
This is the main function:
const hi = () =>
{
if (qajo)
{
return (
<>
Email
Phone
</>
)
}
}
This is the main return:
return (
<>
<a href="#" className="btn btn-dark" onClick={() => setQajo(true)}>Request a quote</a>
{hi}
</>
)
I have a useState variable at the start, called qajo:
const [qajo, setQajo] = useState()
setQajo(false)
When you call setQajo state of component change and React try to recreate them.. but when component is recreated setQajo change state again.. never ending loop. Set initial state in this way:
const [ qajo, setQajo ] = useState(false)
I wanted to setState with react hooks usestate.
First I tried. but it not worked.
const [action, setAction] = useState(null);
...
<button onClick={()=>{
setAction(()=>{console.log('hi')})
}}>test</button>
Second. It worked.
const [action, setAction] = useState({action: null});
...
<button onClick={()=>{
setAction({
action:()=>{
console.log('hi')
}
})}
}>test</button>
Because if I set function directly, the state changed to undefined.
So I pass the function with object type.
But I want to know if there is another way to set state with function.
The issue with your approach is that you are not returning the function in the first place. you are just using the setAction callback to console.log('hi').
<button onClick={()=>{
setAction(()=>{console.log('hi')})
}} />
To fix this issue you need to return a new function in the callback function.
<button onClick={()=>{
setAction(() => () => {console.log('hi')})
}} />
I think what you need is useRef, not useState...!
As documented, if you passed a function to useState, it will set the state to the value it gets after executing the passed function...!
So setAction(()=>{console.log('hi')}) means set the action state to the result of executing this function ()=>{console.log('hi')}, that gives you undefined (because ()=>{console.log('hi')} returns nothing).
If you need to store a function, maybe try this...?
import { useRef } from 'react'
// ... other code
const functionRef = useRef(null)
<button
onClick={() => functionRef.current = () => console.log('hi')}
/>
// ...
I think the problem is with <button />, it should be <button></button>. Here's a JSFiddle where your code is working
const useState = React.useState;
const App = () => {
const [action, setAction] = useState(null);
return (
<button onClick={()=>{
setAction(()=>{console.log('hi')})
}}>Click me!</button>
);
}
const render = () => ReactDOM.render(
<App/>,
document.getElementById('app')
);
render();
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/0.14.0/react-dom.min.js"></script>
<div id="app">
<!-- This element's contents will be replaced with your component. -->
</div>
I am trying to generate a list of buttons using this method. I rewrote it as a test instance and the behaviour is the same - when you render the buttons, the function in onClick is called and cannot be called again by clicking the generated buttons. In this case 1 to 5 are logged.
function App() {
const [buttonList, setButtonList] = useState();
const experimental = async (e) => {
const array = [1,2,3,4,5];
const listItems = array.map((item) =>
<li key={item}>
<button onClick={console.log(item)}>This is a test</button>
</li>
);
setButtonList(listItems);
}
return (
<div className="App">
<header className="App-header">
<button onClick={experimental}>Click to render</button>
<ul>{buttonList}</ul>
</header>
</div>
);
}
Could anyone explain this behaviour to me and/or offer a way of doing this which doesn't do this?
Due to context this. It's must be () => {}. Let's use function and useCallback hook instead.
Hi I have been stuck in a React Function useState. I just want to learn hooks and useState, but I can not have any progress even struggling too much to find a solution. Here is my full react function:
import React, { useState } from 'react';
import './MainPart.css';
function MainPart(props) {
const [orderData_, setOrderData_] = useState(props.orderData);
let topicData_ = props.topicData;
let titleData_ = props.titleData;
let infoData_ = props.infoData;
return (
<div className='MainPart'>
<div className='mainWindow'>{getPics(orderData_)}</div>
<div className='information'>
<div className='moreNewsDivs'>
<div className='moreNewsDiv1'>
<h4>MORE NEWS</h4>
</div>
<div className='moreNewsDiv2'>
<button
className='previous-round'
onClick={setOrderData_(previous(orderData_))}
>
‹
</button>
<button href='/#' className='next-round'>
›
</button>
</div>
</div>
<hr />
<div className='topicDiv'>
<h5 className='topicData'>{topicData_}</h5>
<h5 className='titleData'>{titleData_}</h5>
<h6 className='infoData'>{infoData_}</h6>
</div>
</div>
</div>
);
}
function previous(orderData_) {
let newOrderData;
if (orderData_ === 3) {
newOrderData = 2;
console.log(newOrderData);
return newOrderData;
} else if (orderData_ === 1) {
newOrderData = 3;
console.log(newOrderData);
return newOrderData;
} else {
newOrderData = 1;
console.log(newOrderData);
return newOrderData;
}
}
function next(orderData_) {
let newOrderData;
if (orderData_ === 3) {
newOrderData = 1;
} else if (orderData_ === 2) {
newOrderData = 3;
} else {
newOrderData = 2;
}
return newOrderData;
}
const getPics = picOrder => {
if (picOrder === 1) {
return (
<img
src={require('../assets/desktopLarge/mainImage.png')}
className='MainImage'
alt=''
id='mainImage'
/>
);
} else if (picOrder === 2) {
return (
<img
src={require('../assets/desktopLarge/bridge.png')}
className='MainImage'
alt=''
id='mainImage'
/>
);
} else {
return (
<img
src={require('../assets/desktopLarge/forest.png')}
className='MainImage'
alt=''
id='mainImage'
/>
);
}
};
export default MainPart;
I am getting an error while using useState. Even loading the page fresh and not pressed to anything my buttons onClick event listener activated and As I mentioned before at the topic My Error:
"Error: Too many re-renders. React limits the number of renders to
prevent an infinite loop."
The problem can be found in your onClick prop:
<button className="previous-round" onClick={setOrderData_(previous(orderData_))}>‹</button>
^
Everything between the curly braces gets evaluated immediately. This causes the setOrderData_ function to be called in every render loop.
By wrapping the function with an arrow function, the evaluated code will result in a function that can be called whenever the user clicks on the button.
<button className="previous-round" onClick={() => setOrderData_(previous(orderData_))}
>‹</button>
You can find more information about JSX and expressions in the official docs
https://reactjs.org/docs/introducing-jsx.html#embedding-expressions-in-jsx
Infinite re-render loop
The reason for the infinite loop is because something (most likely setState) in the event callback is triggering a re-render. This will call the event callback again and causes React to stop and throw the 'Too many re-renders.' error.
Technical explanation
To better understand the reason why JSX works this way see the code below. JSX is actually being compiled to Javascript and every prop will be passed to a function in an Object. With this knowledge, you will see that handleEvent() is being called immediately in the last example.
// Simple example
// JSX: <button>click me</button>
// JS: createElement('button', { children: 'click me' })
createElement("button", { children: "click me" });
// Correct event callback
// JSX: <button onClick={handleClick}>click me</button>
// JS: createElement('button', { onClick: handleClick, children: 'click me' })
createElement("button", { onClick: handleClick, children: "click me" });
// Wrong event callback
// JSX: <button onClick={handleClick()}>click me</button>
// JS: createElement('button', { onClick: handleClick(), children: 'click me' })
createElement("button", { onClick: handleClick(), children: "click me" });
Just replace your button with the one below
<button className="previous-round" onClick={() => setOrderData_(previous(orderData_))}>‹</button>
This happens because onClick function if used without an anonymous functions gets called immediately and that setOrderData again re renders it causing an infinite loop. So its better to use anonymous functions.
Hope it helps. feel free for doubts.
When I go through your code, I found something.
Onclick function needs to be arrow function. Onclick is an event and you are just calling a function inside onclick directly. This leads to too many re-renders because you are setting state directly inside the return. That does not work.
Calling setState here makes your component a contender for producing infinite loops. render should remain pure and be used to conditionally switch between JSX fragments/child components based on state or props. Callbacks in render can be used to update state and then re-render based on the change
This above line taken from link here: https://itnext.io/react-setstate-usage-and-gotchas-ac10b4e03d60
Just use Arrow (=>) function:
<button className="previous-round" onClick={() => setOrderData_(previous(orderData_))}>
‹
</button>
use
<button
className='previous-round'
onClick={() => setOrderData_(previous(orderData_))}
>
‹
</button>
This worked for me...