I have a small problem where I have parent class and child class. I want to modify the state that was initialized in parent class so that I can see updated state in parent class. Here's the code:
var Parent = React.createClass({
getInitialState: function(){
return{
my_value: 0
}
},
_increaseValue: function(){
this.state.my_value++;
},
render: function(){
return(
<div><Child /></div>
)
}
});
var Child = React.createClass({
render: function(){
//at button I want to access _increaseValue function of parent
return (
<div>
<button onClick={_increaseValue}>Increase</button>
</div>
);
}
});
Now when user clicks the button in child class I would like to get the updated my_value in parent class, thus my questions are:
Is it possible?
If yes, how it is done?
Is this good practice or no?
Is it possible?
yes, it is possible
If yes, how it is done?
you can pass parent method to child through props, like so
var Parent = React.createClass({
getInitialState: function(){
return {
my_value: 0
}
},
onChangeValue: function () {
var value = this.state.my_value + 1;
this.setState({
my_value: value
})
},
render: function() {
return <div>
<Child
onChangeValue={ this.onChangeValue }
value={ this.state.my_value }
/>
</div>;
}
});
var Child = React.createClass({
_handleClick: function(){
this.props.onChangeValue();
},
render: function(){
return <div>
<h1> { this.props.value } </h1>
<button onClick={ this._handleClick }>Increase</button>
</div>
}
});
Example
Is this good practice or no?
It is good practice
You need to pass function via props into your child component. And when you need to change you call this function. It is normal practice and react way.
Example:
var Parent = React.createClass({
getInitialState: function(){
return{
my_value: 0
}
},
onChildClick: function() {
this.setState({
my_value: this.state.my_value + 1
})
},
render: function(){
return(
<div>
{this.state.my_value}
<Child onClick={this.onChildClick.bind(this)}/>
</div>
)
}
});
var Child = React.createClass({
_handleClick: function(){
this.props.onClick();
},
render: function(){
return (
<div>
<button onClick={this._handleClick}>Increase</button>
</div>
);
}
});
Example on JSFiddle
Related
I'm new to React (also fairly new to Javascript in general) and trying to wrap my head around what can be done with setState to re-render React elements on the page.
Is there a way to use setState in one component to change the state of a completely different element (i.e. components that maybe only share the DOM root node)? I've tried to implement this but am getting the error "myElementOne.setState is not a function".
Is there a another way I should be approaching this?
var App = React.createClass({
render() {
return (
<div>
<ElementOne id="abc12345"/>
<ElementTwo/>
</div>
);
}
});
var ElementOne = React.createClass({
getInitialState() {
return ({isShowing: true});
},
render() {
if (this.state.isShowing) {
return (
<div id="abc12345">
<h1>Hello World!</h1>
</div>
);
} else {
return <div/>;
}
}
});
var ElementTwo = React.createClass({
render() {
return <a href="#" onClick={this.toggle.bind(null,this)}>Click here to Show/Hide!</a>;
},
toggle() {
var myElementOne = document.getElementById("abc12345");
myElementOne.setState({isShowing: false});
}
});
ReactDOM.render(<App/>,document.getElementById('content'));
You can achieve this in the following way: http://codepen.io/PiotrBerebecki/pen/YGEmBE
The idea is to:
Maintain state in your parent component (App)
Pass this state to ElementOne
Pass ability to modify the state by a callback function passed to ElementTwo
Full code:
var App = React.createClass({
getInitialState() {
return ({
isShowingInParent: true
});
},
toggleInParent() {
this.setState({
isShowingInParent: !this.state.isShowingInParent
});
},
render() {
return (
<div>
<ElementOne id="abc12345" isShowing={this.state.isShowingInParent}/>
<ElementTwo toggle={this.toggleInParent}/>
</div>
);
}
});
var ElementOne = React.createClass({
render() {
if (this.props.isShowing) {
return (
<div id="abc12345">
<h1>Hello World!</h1>
</div>
);
} else {
return <div/>;
}
}
});
var ElementTwo = React.createClass({
render() {
return <a href="#" onClick={this.props.toggle.bind(this)}>Click here to Show/Hide!</a>;
}
});
ReactDOM.render(<App/>,document.getElementById('content'));
I'am creating component with input element and button element.
I need to get the input value and use with button, for example. How can I do that?
Here's my code:
var InputSearch = React.createClass({
getInitialState: function() {
return {
value: 'pics'
}
},
handleChange: function() {
this.setState({
value: event.target.value
});
},
render: function() {
return (
<input type="text" value={this.state.value} onChange={this.handleChange} />
)
}
});
var ButtonSearch = React.createClass({
handleClick: function(event) {
console.log(this.state.value); // here's go the input value
},
render: function() {
return (
<button onClick={this.handleClick}>GO! </button>
)
}
});
var Search = React.createClass({
render: function() {
return (
<div>
<InputSearch />
<ButtonSearch />
</div>
)
}
});
React.render(
<Search />,
document.getElementById('result')
);
One issue here is that you are breaking a good rule - separate smart and dumb components. https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0
The way to do this is to have a parent component that holds all the state and functionality of the children and passes all of this down as props...
//Our smart parent
var SearchContainer = React.createClass({
getInitialState : function() {
return {
value : 'pics'
}
},
handleInput : function(event) {
this.setState({value: event.target.value});
},
render : function() {
return (
<div>
<InputSearch value={this.state.value} onChange={this.handleInput} />
<ButtonSearch value={this.state.value} />
</div>
)
}
});
//Our dumb children
var InputSearch = React.createClass({
propTypes : {
onChange : React.PropTypes.func.isRequired,
value : React.PropTypes.string
},
render : function() {
return (
<input type="text" value={this.props.value} onChange={this.props.onChange} />
)
}
});
var ButtonSearch = React.createClass({
propTypes : {
value : React.PropTypes.string
},
handleClick : function() {
console.log(this.props.value); //log value
},
render : function() {
return (
<button onClick={this.handleClick}>GO! </button>
)
}
});
React.render(<Search />, document.getElementById('result'));
Here we pass the handler function down from parent to child so the input doesn't care what happens to the event it fires on change, it just needs to know that it has a prop called onChange that's a function and it invokes that.
The parent (SearchContainer) handles all of that functionality and passes the changed state down to both the button and the input...
hope that helps
Dan
You left out the event in your handleChange.
handleChange: function(event) {
this.setState({
value: event.target.value
});
},
The main architecture of react is the Parent Child / Master Slave principle.
If you want to pass values between components you have to create relations between.
Like for example
You create your master Component with few default states.
var MyMasterComponent = React.createClass({
getInitialState: function(){
...
},
render: function(){
return(
<ChilComponent1 textiwanttopass={this.state.text} />
);
}
});
With that method you are calling the render of another component within a master component. That way you can pass values from states into another component.
In that case you can access the passed text with this.props.textiwanttopass
i have a problem in ReactJS
I want to call this.props.onAction() method from Child class but i have an error:
Uncaught TypeError: this.props.onShotImageClick is not a function
http://jsfiddle.net/01fbL37L/
I want to call this method when buttons are generated dynamically in Parent class.
var btns = ['aaa', 'bbb', 'ccc']
var Child = React.createClass({
render: function () {
return <button onClick={this.handleClick} type="button"> {this.props.text} </button>;
},
handleClick: function () {
this.props.onAction("super text");
},
});
var Parent = React.createClass({
render: function () {
var buttons = btns.map(function(btn){
return <Child onAction={this.superAction} text={btn} />;
});
return <p>{buttons}</p>;
},
superAction: function (text) {
alert('The Child button say: ' + text);
}
});
React.renderComponent(<Parent />, document.body);
If i call it directly in "return" it works..
http://jsfiddle.net/f2ty4jkm/
Thanks.
Set this to .map callback, because in your case this refers to window not to your Parent object
var buttons = btns.map(function(btn) {
return <Child onAction={this.superAction} text={btn} />;
}.bind(this));
Example
as shown in the example below, I'd like MyComponent to dynamically attach an "onClick" event to its children. The onClick event should fire alertView that should be able to call the clicked element method "getValue".
JSFiddle: http://jsfiddle.net/2g638bp8/
How to do this? Thanks
var MyComponent = React.createClass({
alertValue: function () {
// RETRIEVE THE CHILD HERE
alert(child.getValue());
},
render: function () {
var children = React.Children.map(this.props.children, function (c, index) {
return React.addons.cloneWithProps(c, {
ref: 'child-' + index
});
});
return (
<div>
{children}
</div>
);
}
});
var MySubComponent = React.createClass({
getValue: function () {
return this.props.val;
},
render: function () {
return (
<div>{this.props.val}</div>
);
}
});
React.render(
<div>
<MyComponent>
<MySubComponent val="1" />
<MySubComponent val="2" />
<MySubComponent val="3" />
</MyComponent>
</div>,
document.getElementById('container')
);
You can't call methods on child components in React. You can only set properties. (The child is actually a ReactElement which contains information about the class and associated properties. It is not an instance of the component you created).
So, you could think about this a slightly different way and move the onClick to the MySubComponent:
var MyComponent = React.createClass({
onHandleGiveValue: function (value) {
alert(value);
},
render: function () {
const children = React.Children.map(this.props.children, child => React.cloneElement(child, { onGiveValue: this.onHandleGiveValue.bind(this) }));
return (
<div>
{children}
</div>
);
}
});
var MySubComponent = React.createClass({
handleClick: function() {
this.props.onGiveValue(this.props.val);
},
getValue: function () {
return this.props.val;
},
render: function () {
return (
<div onClick={ this.handleClick } >{this.props.val}</div>
);
}
});
React.render(
<div>
<MyComponent>
<MySubComponent val="1" />
<MySubComponent val="2" />
<MySubComponent val="3" />
</MyComponent>
</div>,
document.getElementById('container')
);
By doing that, your code can pass the current value as an event to the parent component. I've created a new event from the MySubComponent class named onGiveValue. That for now just passes the value from this.props.val. But, it could of course be anything.
Pass the parent callback to the subComponent, one dont need a reference for the child component.
React prefers composition design pattern, So your parent component should contains those three subComponent.
JS Fiddle: http://jsfiddle.net/68vt3umg/
var MyComponent = React.createClass({
handleChildClick: function (e, childValue) {
alert(childValue);
},
render: function () {
return (
<div>
<MySubComponent val="1" onSubClicked={this.handleChildClick}/>
<MySubComponent val="2" onSubClicked={this.handleChildClick}/>
</div>
);
}});
var MySubComponent = React.createClass({
getValue: function () {
return this.props.val;
},
handleOnClick: function (e, value) {
this.props.onSubClicked(e, this.props.val);
},
render: function () {
return (
<div onClick={this.handleOnClick}>{this.props.val}</div>
);
}
});
React.render(
<div>
<MyComponent />
</div>,
document.getElementById('container')
);
I'm trying to bind a value to a div with react so that I can maintain state for that element (eg. on-off) It looks like I should be using LinkedStateMixin, but my experiment below proves that react doesn't support arbitrary attributes for block level elements. Both elements have default values but the div e.target.value returns undefined from its onclick handler whereas the input element value has been properly set. Any idea how to bind data to the div? Thanks!
var Component = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return {message: 'Hello!'};
},
render: function () {
var valueLink = this.linkState('message');
var handleClick = function(e) {
console.log(e.target.value);
valueLink.requestChange(e.target.value);
};
return (
<div>
<input type="text" onClick={handleClick} defaultValue={valueLink.value} />
<div onClick={handleClick} defaultValue={valueLink.value}>
{this.state.message}
</div>
</div>
);
}
});
React.render(<Component />, document.body);
http://jsfiddle.net/su8r5Lob/
var Component = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return {
message: 'Hello!',
active: false
};
},
inputClick : function(e) {
console.log(e.target.value);
},
toggleActive : function(e){
console.log('div state', this.state.active);
var newState = !this.state.active;
this.setState({active: newState});
},
render: function () {
var cx = React.addons.classSet;
var valueLink = this.linkState('message');
var classes = cx({
'base-class': true,
'element-active': this.state.active
});
return (
<div>
<input type="text" onClick={this.inputClick} defaultValue={valueLink.value} />
<div onClick={this.toggleActive} className={classes}>
{this.state.message}
</div>
</div>
);
}
});
React.render(<Component />, document.body);
http://jsfiddle.net/su8r5Lob/1/
The reason your code does not work is because <div> elements do not have a value property. Only elements that receive user input have it. So when handleClick is called, valueLink.requestChange receives undefined as a parameter.
I've updated your Fiddle a little bit, and now it does support two-way binding for the onChange event.
var Component = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return {message: 'Hello!'};
},
render: function () {
var valueLink = this.linkState('message');
var handleClick = function(e) {
console.log(e.target.value);
valueLink.requestChange(e.target.value);
};
return (
<div>
<input type="text" onChange={handleClick} value={valueLink.value} />
<input type="text" onChange={handleClick} value={valueLink.value} />
</div>
);
}
});
React.render(<Component />, document.body);
But, if you want to bind it to a div element, I give you this suggestion. I'm not sure if it is exactly what you expect, but here it is:
var Component = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return {message: 'Hello!'};
},
render: function () {
var valueLink = this.linkState('message');
var handleClick = function(e) {
console.log(e.target.value);
valueLink.requestChange(e.target.value);
};
return (
<div>
<input type="text" onChange={handleClick} value={valueLink.value} />
<div onClick={handleClick.bind(this, {target: {value: 'someDivValue'}})} defaultValue={valueLink.value}>
{this.state.message}
</div>
</div>
);
}
});
React.render(<Component />, document.body);
Note that I gave the div a default value that is going to be set to the valueLink everytime the user clicks it. And I had to change the event on the input to onchange so it can update its value when the user types something.