ReactJS: Hiding a text produces an error: Maximum update depth exceeded - javascript

I just cant hide my text (Header) using a button in a class form. I try this code below:
constructor(props){
super(props)
this.state = {
showHeader: true,
}
}
And I render the state above using setState:
render () {
return (
<div>
{this.state.showHeader && <Header /> }
<button onClick={ this.setState({showHeader: false})} >Hide</button>
</div>
I know this is a stupid question but I cant help myself because Im a totally beginner. But I did this right using function and I just want try to convert it using a class. This is what I did using function:
const [show, setShow] = React.useState(true);
const hideHeader = () => {
setShow(!show)
}
And return this:
return (
<div>
{show && <Header />}
<button onClick={hideHeader}>Hide Header</button>
</div>
)

Right now you're calling setState() in your render function. That's going to cause problems because setState causes your render method to be called, and if your render method calls setState directly, you get caught in a loop.
What you need to do is call it in an event handler instead:
// bad
onClick={this.setState({showHeader: false})}
// good
onClick={() => this.setState({showHeader: false})}
So your button should look like this:
<button onClick={() => this.setState({showHeader: false})} >Hide</button>
From the docs:
The render() function should be pure, meaning that it does not modify component state, it returns the same result each time it’s invoked, and it does not directly interact with the browser.

Related

How can I make a component render onClick in a React functional component?

I'm a bit surprised I'm having trouble finding this online, but I can't seem to find an example of how to do this in a React functional component. I have a React component that I would like to render when I click a button. Right now the function fires and I can see my console.log firing, however the component isn't rendering. My first guess was that it won't render because React doesn't know to update the view, however I added boolean via useState and it still won't render. What am I doing wrong?
Below is the relevant code. How can I get the component in addSection to render?
const FormGroup = ({index}) => {
const [additionalSection, setAdditionalSection] = useState(false);
const addSection = form => {
setAdditionalSection(true);
console.log('form', form);
return additionalSection && (
<div key={form.prop}>
<p>This should render</p>
<AdditiveSection
form={form}
register={register}
errors={errors}
/>
</div>
);
};
...
return (
...
<FormAdd>
<LinkButton
type="button"
onClick={() => addSection(form)}
>
span className="button--small">{form.button}</span>
</LinkButton>
</FormAdd>
);
You should change your state (or a prop in your useEffect dependency array in case you had one) in order to force a rerender. In this case:
setAdditionalSection(prevState=>!prevState);
A state change like the one you are calling, will trigger a re-render.
But all html to be rendered must be included in the functional components return statement.
The elements you want to render can be conditionally rendered like this:
const FormGroup = ({index}) => {
const [additionalSection, setAdditionalSection] = useState(false);
const addSection = form => {
setAdditionalSection(true);
console.log('form', form);
};
...
return (
...
<FormAdd>
<LinkButton
type="button"
onClick={() => addSection(form)}
>
<span className="button--small">{form.button}</span>
</LinkButton>
{additionalSection &&
<div key={form.prop}>
<p>This should render</p>
<AdditiveSection
form={form}
register={register}
errors={errors}
/>
</div>
}
</FormAdd>
);

Way to render a new component onClick in react js

Am trying to render a new component onclick a button in react js. Am using functional components and I can't handle it. Eg: am in the UserManagement component and on a button click I need to render another component named employee management.
You can conditionally render your component.
Example :
EmployeeManagement.js
const EmployeeManagement = () => {
....
return (
<div>
EmployeeManagement
</div>
);
}
UserManagement.js
const UserManagement = () => {
const [hasRender, setRender] = useState(false);
const onShow = React.useCallback(() => setRender(true), []);
return (
<>
<button onClick={onShow}>Show Employee Management</button>
{hasRender && <EmployeeManagement />}
</>
)
}
One way to do this would be to add a local state in UserManagement,
that holds a boolean value indication whether the component should be hidden or shown.
Then you will have something like:
function UserManagement() {
const [compIsShown, setCompIsShown] = useState(false);
return (
// Whatever else you're rendering.
<button onClick={() => setCompIsShown(true)}>...</button>
{compIsShown && <OtherComp />}
)
}
What will happen is that compIsShown will initialize as false,
so this condition compIsShown && <OtherComp /> will prevent it from rendering.
Then, when you click the button, the state will set, causing a re-render, except now the condition will be true, so <OtherComp> will be rendered.
There are other ways to go about this.
Depends mostly on the use-case.
use a visible state & toggle it in onClick:
const [visible, setVisible] = useState(false)
onClick = () => {setVisible(true)}
then render it like this:
{visible && <EmployeeManagement onClick={onClick} />}

React - TypeError: Cannot read property 'setState' of undefined (Arrow functions)

I am not able to use setState. My code looks something like:
const FormComp = () => {
const [reader, setReader] = React.useState(0);
//rest of the code
};
const Ques1 = () => {
return (
<>
<button onClick={() => {
this.setState({ reader: "1" });
}}>Click</button>
</>
)
};
This is just a short version of the code. I'm facing problem in this. Please someone help me out.
This code is in same file.
UPDATE:
tried setReader but it throws an error saying setReader is not defined
When you use React.useState you don't do this.setState, in this example you would just do:
<button onClick={() => {
setReader("1");
}}>Click</button>
Should use like this:
import React from 'react';
function App() {
const [reader, setReader] = React.useState(0);
const FormComp = () => {
//rest of the code
return <div>Clicked {reader} times</div>
};
const Ques1 = () => {
return (
<button onClick={() => setReader(reader+1)}>Increase</button>
)
};
return (
<div className="App">
<FormComp />
<Ques1 />
</div>
);
}
export default App;
You can set whatever value you want in setReader function.
since you're using the useState hook, you should call setReader instead of this.setState.
When you use react hooks and functional components, you can throw away (by moment) the concepts about this.setState
Instead to use this.setState({ reader: "1" }) for const [reader, setReader] = React.useState(0); useState Hook. You should use setReader(1) or setReader("1") (According to your old "this.setState({reader: "1"})")
Button onClick be like:
<button onClick={() => setReader(1)}>
Click
</button>
There are two issues in your code.
You're using setState while using react hook useState
useState in being used in one component, trying to access it on another component
So, decide where do you need it, or you want to pass it as prop and/or lift state up?
And use:
onClick={() => setReader(1)}

Call a React Component with an onClick event

I need to call a Component (ExampleComp), and when the button is clicked, call againthe component (ExampleComp). The idea is to call the Component(ExampleComp) as many times as you press the button.
function newComponent{
<ExampleComp/>
}
------
return(
<div>
<ExampleComp/>
<Button className="btnNew" onClick=
{newComponent}> Create a new Component</Button>
</div>
)
Actually i don't know how to do it exactly and i would apreciate your help.
You can use the state for this purpose. Let's say your state is something like this:
this.state = { items: [] };
You can render all the items like the following example:
return (
<div>
{this.state.items.map(item => {
return <ExampleComp exampleProp={item.exampleProp} />;
})}
<Button className="btnNew" onClick={newComponent}>
Create a new Component
</Button>
</div>
);
And finally, you can push an item into the state, and React will take care of the rest.
function newComponent{
newItem = { exampleProp: 'Something?' };
this.setState((state, props) => ({ items: [...items, newItem] }));
}
This will do the job. I just used "exampleProp" to be an example but you don't have to use it. Actually, the state can be just a number too. The important part is using state in every user interface change.
render(){
return (
<Button className="btnNew" onClick={ this.setState({ clicked:true }) }>Create a new Component</Button>
{
this.state.clicked ? {newComponent} : null
}
)
}
This would help but though not recommended by me as setState will re-render(load) the component again onClick.

Cannot update during an existing state transition in stateless component

I have the following warning :
Warning: setState(...): Cannot update during an existing state transition (such as within render or another component's constructor).
with React-redux-router that I understand, but do not know how to fix.
This is the component that is generating the warning.
const Lobby = props => {
console.log("props", props)
if (!props.currentGame)
return (
<div>
<input type="text" ref={input => (roomName = input)} />
<button
className="button"
onClick={() => {
props.createRoom(roomName.value)
}}
>
Create a room
</button>
</div>
)
else
return (
<div>
{props.history.push(`/${props.currentGame}[${props.username}]`)}
</div>
)
}
export default Lobby
What I'm doing here is that my component receives the currentGame property from the Redux store. This property is initialized as null.
When the user creates a game, I want to redirect him on a new URL generated by the server that I assign inside the property currentGame with a socket.io action event that is already listening when the container of the component Lobby is initialized.
However, since the currentGame property changes, the component is re-rendered, and therefore the line
{props.history.push(`/${props.currentGame}[${props.username}]`)}
generates a warning since the property currentGame now has a value, and the history property should not get modified during the re-render.
Any idea on how to fix it ?
Thanks!
You should not write props.history.push in render, instead use Redirect
const Lobby = props => {
console.log("props", props)
if (!props.currentGame)
return (
<div>
<input type="text" ref={input => (roomName = input)} />
<button
className="button"
onClick={() => {
props.createRoom(roomName.value)
}}
>
Create a room
</button>
</div>
)
else
return (
<div>
<Redirect to={`/${props.currentGame}[${props.username}]`} />
</div>
)
}
Do one thing, instead of writing the condition and pushing with history.push(), just put the code inside componentDidMount() if you are trying to do in the beginning.
componentDidMount(){
if(condition){
history.push('/my-url');
}
}

Categories