React, Local cached variable and firing onclick on render - javascript

I am trying to make a local variable for each component instance, something like a little cache because it is storing information that toggles something and does not need to be on the state/store. So I have attempted it like so:
Setting a default prop to keep my info in :
getDefaultProps: function getDefaultProps() {
return {
showPreviewModal: { value: false,
writable: true
}
};
},
Setting a function to toggle this prop :
togglePreviewModal: function togglePreviewModal() {
this.props.showPreviewModal = !this.props.showPreviewModal;
},
And having that function fired by a click function
<button className="btn btn-default btn-blue previewAsset" onClick={() => this.togglePreviewModal() }>
I thought this would work in theory, but the onclick is firing immedietly on render. I googled this issue and it seems like the best result is to change the click function to :
{() => { this.props.togglePreviewModal() }}
However this does not work either, the click function is still firing immediately.

You can't directly mutate props like that - since props are explicitly passed down from a parent component, you'd need to change the prop at the source. Presumably, it originates from the state of a component somewhere up the hierarchy.
To do that, you'd pass down a function along with the prop that changes it at the source (using setState()). Here's an example:
var ParentComponent = React.createClass({
togglePreviewModal: function() {
this.setState({
showPreviewModal: !this.state.showPreviewModal
};
},
getInitialState: function() {
return {
// Unnecessary but providing for clarity
showPreviewModal: false
};
},
render: function() {
// This is for whatever values you were mapping over
var childComponents = ...map(function() {
return <ChildComponent togglePreviewModal={this.togglePreviewModal} />;
});
if (this.state.showPreviewModal) {
return (<div>
<Modal />
{childComponents}
</div>);
} else {
return (<div>
{childComponents}
</div>);
}
}
});
var ChildComponent = React.createClass({
render: function() {
return <button
className="btn btn-default btn-blue previewAsset"
onClick={this.props.togglePreviewModal} />;
}
});
Note that I'm not invoking the function in the onClick of the <button>, just passing in the prop (which is a function).

Related

ReactJS state change is inconsistent

When I have a button class called "DrawButton", that has this render
render() {
return(
<Button
onClick={this.props.toggleDraw.bind(this)}
style={{
backgroundColor: this.props.drawMode ? 'red' : 'blue'
}}
>
Draw
</Button>
);
}
And in parent App.js the state gets defined
state = {
drawMode: false
}
and there is a handler function
toggleDraw = (e) => {
console.log('App.js drawMode:' + this.state.drawMode);
this.setState({
drawMode: !this.state.drawMode
});
console.log('App.js drawMode:' + this.state.drawMode);
}
And finally the button:
render() {
return (
<div className="App">
<DrawButton
toggleDraw={this.toggleDraw}
drawMode={this.state.drawMode}
/>
</div>
);
}
The state doesn't get updated properly.
It outputs the following:
First click on the Button
App.js drawMode:false
App.js:27
App.js drawMode:false
App.js:31
Before the setState ran, the drawMode is false after setState ran, the drawMode is still false.
But the button still gets a red background.
Second click on the Button:
App.js drawMode:true
App.js:22
App.js drawMode:true
App.js:26
But the button is blue again despise drawMode in state is set to true.
Why is this inconsistency happening?
Firstly, your bind was used incorrectly, in your DrawButton onClick handler, just call this.props.toggleDraw.
This code : this.props.toggleDraw.bind(this) should be in the constructor of App.js file.
Secondly, do not use the console.log to check the value of state after setting, because the setState function runs asynchronously, use setState callback to check the value after setting:
toggleDraw = (e) => {
console.log('App.js drawMode:' + this.state.drawMode);
this.setState(
{ drawMode: !this.state.drawMode },
() => console.log('App.js drawMode:' + this.state.drawMode)
),
}

Cannot update during an existing state transition - Not using any illegal setState()

Some one Please Help me with this error
Cannot update during an existing state transition
When I am rendering this I'm getting error like below
Cannot update during an existing state transition (such as within
render or another component's constructor). Render methods should be
a pure function of props and state; constructor side-effects are an
anti-pattern, but can be moved to componentWillMount.
I have tried putting this.props.ifListChanged(this); this code inside the componentWillUpdate and componentDidUpadate but it is taking too much time but without errors(almost 2 mins).
import React from 'react';
import ListItemComponent from './ListItem.jsx';
import DropDownButtonComponent from './DropDownButton.jsx';
import DropDownStyle from '../../../../css/sass/drop-down.scss';
module.exports = React.createClass({
handleClick: function () {
this.setState({open: !this.state.open});
},
getInitialState: function () {
return {
open: false,
//listItems: this.props.listItems,
selectedItems:[],
title: this.props.dropdownTitle
}
},
handleItemClick: function (item) {
var selectedItems = [];
if(this.props.multiple == true){
selectedItems = this.state.selectedItems;
if(selectedItems.indexOf(item)==-1){
selectedItems.push(item);
}else{
selectedItems.splice(selectedItems.indexOf(item),1)
}
this.setState({
title: this.state.selectedItems.length+" selected",
selectedItems: selectedItems
});
} else{
selectedItems = [];
selectedItems.push(item);
this.setState({
title: item,
selectedItems: selectedItems,
open: false
});
}
//this.sendStateToParent();
},
sendStateToParent: function(){
this.props.ifListChanged(this);
},
handleTextChange: function (event) {
var filteredItems = [];
this.props.listItems.map(function(item){
if(item.toLowerCase().search(event.target.value.toLowerCase()) != -1){
filteredItems.push(item);
}
},this);
this.setState({
listItems: filteredItems
});
},
clearSelected: function(){
this.setState({
title: this.props.dropdownTitle,
selectedItems: [],
});
},
render: function () {
this.props.ifListChanged(this);
var index = 0;
var list=[];
if (this.state.listItems != undefined) {
list = this.state.listItems.map(function (item) {
return (
<ListItemComponent
key={index++}
item={item}
whenItemClicked={this.handleItemClick}
className={this.state.selectedItems.indexOf(item) != -1 ? "active" : ""}
/>);
}.bind(this));
} else {
list = this.props.listItems.map(function (item) {
return (
<ListItemComponent
key={index++}
item={item}
whenItemClicked={this.handleItemClick}
className={this.state.selectedItems.indexOf(item) != -1 ? "active" : ""}
/>);
}.bind(this));
}
return <div className="btn-group bootstrap-select form-control">
<DropDownButtonComponent
whenClicked={this.handleClick}
title={this.state.title}
/>
<ul className={"dropdown-menu inner dropdown-menu " + (this.state.open ? "show" : "") }>
{this.props.search? <li><input type="text" style={{margin:"auto", maxWidth:"96%"}} onChange={this.handleTextChange} placeholder="Search"/></li> :""}
<li className="disabled"><a>Select from below list {this.props.multiple ? <i title="clear all" style={{fontSize:"15px"}} onClick={this.clearSelected} className="text-danger fa fa-ban pull-right"></i>: ""}</a></li>
{list}
</ul>
</div>
}
});
ListItem.jsx
import React from 'react';
module.exports = React.createClass({
handleClick: function() {
this.props.whenItemClicked(this.props.item);
},
render: function() {
return <li onClick={this.handleClick} className={this.props.className}>
<a>{this.props.item}</a>
</li>
}
});
DropDownButton.jsx
import React from 'react';
module.exports = React.createClass({
render: function() {
return <button onClick={this.props.whenClicked} className="btn dropdown-toggle btn-default" type="button">
<span className="filter-option pull-left">{this.props.title}</span>
<span className="bs-caret"><i className="fa fa-chevron-down"></i></span>
</button>
}
});
Advance thanks to the one who helps me. Thank you.
I think you have a prop/state design issue. Your this.props.ifListChanged(this) inside your render function is very suspicious. Your render function should NOT need to signal anything to parent. Parent already knows all the props it sent down, and if parent needs to know about the state, then it most likely should not be state in the first place.
From what I can gather from your code,
your List component receives an unfiltered list of items as props
and it has a state that keeps track of filtereditems and of selecteditems.
This is a nice setup if the result of both need to be sent somewhere with another action inside the component itself (e.g. a process-selection button or something).
Then (and only then) would you send the state to parent or to somewhere else.
If the parent needs to know about both all the time (for instance when the process-button or process-action is somewhere else), then it is better to:
define some handleFilterUpdate and 'handleSelectionUpdate` methods inside the parent and pass these as props to the child.
also pass the filtered list and selection from the parent to the child.
call the this.props.handleFilterUpdate and 'this.props.handleSelectionUpdate` from the child whenever something happens with selection or filters.

Communicate between parent and child component in React.js

Just meet a problem about communication between parent and child component in React.
Child
var Child = React.createClass({
getInitialState() {
return {
childState: this.props.state,
};
},
changeState(e) {
this.setState({e.target.id});
},
render: function () {
return (
<button id='1' onClick={this.changeState}>1</button>
<button id='2' onClick={this.changeState}>2</button>
);
},
});
Parent
var Parent = React.createClass({
getInitialState() {
return {
parentState: '1',
};
},
render: function () {
return (
<Child state=this.state.parentState />
);
},
});
So right now Parent will pass the initial state '1' to child, I want the child component can change both child and parent's state. For example, when click the second button, both child and parent state are set to '2'. How can I achieve this? Thank guys!
to achieve this behaviour you need to communicate with your parent component through props.
var Child = React.createClass({
render: function () {
return (
<button id='1' onClick={this.props.changeState}>1</button>
<button id='2' onClick={this.props.changeState}>2</button>
);
},
});
var Parent = React.createClass({
getInitialState() {
return {
parentState: '1',
};
},
changeState: function(){
this.setState({parentState: e.target.id});
},
render: function () {
return (
<Child changeState={this.changeState} state={this.state.parentState} />
);
},
});
The idea behind this is, that you are passing down the changeState function from your parent Component to your child Component as a function and make it accessible through props. That way when you call the prop function in your child Component - the function in the parent Component will get executed.
That way you also don't need to keep a second "separate" state in your child component because the state of the parent component will be available in both and have the same value in both.
Pardon me for any typing mistakes - I am at the office but since you had no answer yet I wanted to help.

Can I set the children props in a react component from its parent?

Is it possible in react to do something like this:
var App = React.createClass({
getInitialState: function(){
return {
children: [<div/>, <div/>],
comp: ''
};
},
componentWillMount: function(){
this.setState({
comp: <SomeComponent children={this.state.children}/>
});
},
render: function(){
return (
<div>
{this.state.comp === '' ? this.state.children : this.state.comp}
</div>
);
}
});
When I try to do something similar to this I get: Uncaught TypeError: Cannot read property '_currentElement' of null so I assume the answer is no, but I figure there has to be some way considering
<SomeComponent>
<div/>
</SomeComponet>
where <SomeCompent/> renders a <div/>, is valid. However in this particular case I get the same error doing that, but if you look at something like React-Bootstrap https://react-bootstrap.github.io/, it has to be possible.
Why do you want to pass html tags as state? I'm not saying is bad, but there's always a better solution to what you asking. Let's say a child component passing a state Boolean true or false to parent component( Flux - Action by child component pass to store, parent components can pick up the state with onChange event). With that you could invoke the parent element to render different view.
_onChange: function() {
this.setState(this._getStateFromStores());
},
render: function() {
var view;
if (this.state.childAction) {
view = <SomethingTrue/> ;
}
if (!this.state.childAction) {
view = <SomethingFalse/> ;
}
return (
<div>
{view}
</div>
);

Call a 'Fathers' function form a 'Children' component in ReactJS

I have the next component 'Father' that contains a 'Children' component in React js.
var Father = React.createClass({
render: function () {
return (
<div>
<Children/>
</div>
);
},
onUpdate: function(state) {
this.setState(state);
} });
I want to call the onUpdate function on the father from the children BUT without calling the 'Children' method 'componentDidUpdate' because I'm using that method for some other thing that breaks my application.
How can I do that?
Pass it down in properties. If you need to update only specific parts and prevent your children from updating, use the method shouldComponentUpdate
var Father = React.createClass({
render: function () {
return (
<div>
<Children onUpdateCallback={this.onUpdate}/>
</div>
);
},
onUpdate: function(state) {
this.setState(state);
}
});
var Child = React.createClass({
render: function () { ... },
shouldComponentUpdate: function (prevProps, prevState) { ... return false}
});
If your Children can't/shouldn't update while the Parent does, I think you are probably doing something wrong, but good luck.

Categories

Resources