React having to toggle state twice for response - reactjs

I'm pretty new to React so I made sure to research this as well as I can.
But for some reason when I'm rendering, I have to initiate the state manually for a response.
Here is a portion of it:
export class exampleOne extends React.Component {
constructor(props){
super();
this.state = {
buttonToggleState: true,
secondToggleState: true
}
componentDidMount() {
this.setupPage();
}
buttonToggle() {
var newToggleState = !this.state.buttonToggleState;
this.setState({
buttonToggleState: newToggleState,
secondToggleState: !this.state.secondToggleState
});
}
render() {
return (
<input type="checkbox" onChange={this.buttonToggle.bind(this)}
defaultChecked={this.state.secondToggleState} />
It works, just that I have to click the checkbox twice for it to change to actually render. It changes states, just no rendering until the second click, then it works fine after.

Related

Updating react component from sideBar menu

I have a simple react app that consists of 3 components:
1. SideBar that contains links
2. ItemList that contains data in a table
3. Wrapper that wraps both of them (I understood from some posts here that it is sometimes useful, as I want to update the ItemsList component after clicking on different links on the sideBar).
What I have working now:
In the main Wrapper component:
render() {
return (
<div>
<SideMenu handleClick={this.handleClick} />
<ItemsList url={this.state.currentUrl} />
</div>
);
}
as soon as the app starts, using componentDidMount() in ItemsList component, it fetches there the data, and display it. that works fine.
Problem is, when I click the links in the sideMenu component, I am changing the currentUrl in the state of the main wrapper, so then it will get re-rendered by the new url:
handleClick() {
this.setState({ currentUrl: 'here I put the new address to fetch from'});
}
but what gets fetched is data that is located in the previous url, not the one I had just changed it to.
Basically, right after I debug and check the state after I had changed it, the currentUrl stays the previous one, and then it re-renders the ItemList with the previous url.
my question is, how do I Change the content of the itemList, using this handleClick() method? Hopefully I will get some insights. thank you very much, I would appreciate your assistance.
the main wrapper Code:
class MainWrapper extends React.Component {
constructor() {
super();
this.state = {
currentUrl: 'current url to fetch from...',
data: []
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({ currentUrl: 'the new url ' });
}
render() {
return (
<div>
<SideMenu handleClick={this.handleClick} />
<ItemsList url={this.state.currentUrl} />
</div>
);
}
}
my Itemlist Component:
class ItemsList extends Component {
constructor(props) {
super(props);
this.state = { url: props.url, data: [] };
}
componentDidMount() {
return fetch(this.state.url)
.then((response) => response.json())
.then((responseJson) => {
this.setState({ data: responseJson.data });
})
}
render() {
return (
displaying the table html tags..
}
</div>
)
}
}
You could the componentDidUpdate life cycle method in your itemList component. Each time the url changes, the listItem would presumably re-render based on what I understood from your question, so the componentDidUpdate method will fire. It is in this method where you can check for the new url and make the new request.
See more here.

Change status of state variable in Child Component of react.js

I have a parent component like below. I have a button here named View.
class DataTable extends Component {
constructor(props) {
super(props);
this.state = {
modalOpen: false,
};
this.view = this.view.bind(this);
}
view() {
this.setState({ modalOpen: true });
}
render() {
return (
<div>
<button className="mini ui button" onClick={this.view}>
<i className="user icon"></i>
View
</button>
<ModalBody modelStatus = {this.state.modalOpen}/>
</div>
)
}
}
I have a child component like below
class ModalBody extends Component {
state = { modalchildOpen: false }
componentDidMount() {
if(this.props.modelStatus) {
this.setState({ modalchildOpen: true })
console.log('yes')
}
else {
this.setState({ modalchildOpen: false })
console.log('no')
}
}
render() {
return (
<div>
<Modal open={this.state.modalchildOpen}/>
</div>
)
}
}
I would like to change status of modalchildOpenfrom false to true while clicking on Button View. In another action I would like to change status of modalchildOpenfrom true to false in the child component.
I agree with #lustoykov about how you would normally set the modal open/closed value through state. However, if you want to update the state based on props passed down from the parent, what you’re probably looking for is the componentWillReceiveProps life cycle method. This method runs anytime your child component receives props and you can compare the old props to the new props. You can then set the state inside that function.
Reference this link:
https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops
Please note, there is newer version of this life cycle method called getDerivedStateFromProps. Be sure to check your versioning and see if you can use the new method as the old one will eventually become deprecated.
I solved the issue using below code.
componentWillReceiveProps(nextProps){
this.setState({
modalchildOpen: nextProps.modelStatus,
})
}
Thanks all.

get height of image on load and send to parent

I am trying to get the height of an image when it has loaded and send it back to the parent component, but it is causing infinite rerendering.
This is a prototype of my code:
import MyImage from './images/myImage.jpg';
class Image extends React.Component {
constructor(props) {
super(props);
this.state = {
height: 0
}
}
getHeight = (e) => {
const height = e.target.getBoundingClientRect().height;
this.setState({
height: height
});
this.props.setUnitHeight(height);
}
render() {
const image = this.props.image;
return (
<img src={image.name} onLoad={(e)=>{this.getHeight(e)}} />;
);
}
}
class App extends Component {
constructor(props) {
super(props);
const initUnit = 78.4;
this.state = {
unit: initUnit
}
}
setUnitHeight = (height) => {
this.setState({
unit: height
});
}
render() {
return (
<div>
<Image image={MyImage} setUnitHeight={this.setUnitHeight} />
</div>
);
}
}
I have tried sending unit as a prop and then checking in shouldComponentUpdate whether it should be rerender or not, but that did nothing.
The issue you are having is that React by default re-renders the component every time you call this.setState. In your case what this is happening:
You load your Image component
It loads the <img> tag and fires the onLoad function
The onLoad function calls this.setState
Repeat these steps forever
You should take a look at the React's lifecycle components methods (https://reactjs.org/docs/react-component.html#the-component-lifecycle) to understand this better.
My suggestion is: do not keep the image height in the state, unless you really need it. If you really need to maintain it in the state for some reason you can use the lifecycle method shouldComponentUpdate (https://reactjs.org/docs/react-component.html#shouldcomponentupdate`) to prevent it from rendering.
Your code seems redundant, setState({}) isn't necessary in <Image> class. If you are using the same props throughout the app, then you should be setting it at one place and be using the same prop all over. For example -
getHeight = (e) => {
const height = e.target.getBoundingClientRect().height;
//setState not needed here
this.props.setUnitHeight(height);
}
That should do it.
P.S: Do check if your this references aren't going out of scope.

How to onclick method set for only one input?

First please click for SS.
Right now I have 2 input which has value credit-card and paypal.
I set an onClick event for CreditCard to provide card informations.It works fine but problem is:
Card details doesn`t disappear when I click paypal input. It works just if I click CreditCart input again. I want to make it disappear even I click paypal input. I mean card details should seem only by clicking Credit Card input.
class CreditCart extends React.Component {
constructor(props) {
super(props);
this.state = {show:false};
this.handleClick = this.handleClick.bind(this);
}
handleClick () {
this.setState({ show : !this.state.show})
}
render () {
return (
//2 input here credir-cart has onClick
{this.state.show && <CreditCart/>
}
Second component which includes cart information part:
class CreditCart extends React.Component {
constructor(props) {
super(props);
}
render () {
// information part
}
Your handleClick method is wrong. The setState method is asynchronous and it will try to execute it in batches which means that the previous value might not be updated yet.
Change it to
handleClick() {
this.setState(function (prevState, props) {
return {
show: !prevState.show
};
});
}
See State Updates May Be Asynchronous
I think something like the following should work for you...
class SomeComponent extends Component {
constructor() {
this.state = {
toggle: false
};
}
render() {
return (
<div>
{this.state.toggle
? <CreditCardComponent />
: <PaypalComponent />}
<button
onClick={e => this.setState({ toggle: !this.state.toggle })}
>
Toggle
</button>
</div>
);
}
}

State directly on "this"

A lot of people use properties directly on this (e.g this.clickCount) instead of this.state object and sometimes there's like 20 different properties attached directly to this.
Is this.state purely for organization or is there something else about it? Why are so many people / projects not using this.state?
Both following examples work exactly the same way.
Code example with state:
class Clicker extends React.Component {
constructor() {
super()
this.state = {
clickCount: 0
}
this._onClick= this._onClick.bind(this)
}
render() {
return (
<button onClick={this._onClick}>
Clicked {this.state.clickCount} times
</button>
)
}
_onClick() {
this.setState({
clickCount: this.state.clickCount + 1
})
}
}
Code example without state:
class Clicker extends React.Component {
constructor() {
super()
this._onClick= this._onClick.bind(this)
}
render() {
return (
<button onClick={this._onClick}>
Clicked {this.clickCount ? this.clickCount : 0} times
</button>
)
}
_onClick() {
this.clickCount = (this.clickCount ? this.clickCount : 0) + 1
}
}
There are cases when you'll want just instance variables that are unrelated to state. For these just do something like this.<INSTANCE-VARIABLE>.
When you want your component to re-render whenever a value is changed, you're better off attaching that value to state and modifying it using this.setState(..).
The first example will trigger a re-render of the component when _onClick is called because the state is changed.
The second example will not trigger a re-render of the component when _onClick is called, so you might not see the updated value for some time (until something else makes the component render again).

Resources