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
Related
Alright so I'm tinkering with ReactJS and working on simple examples, everything working great and I already feel it has improved my productivity. Now I am working on a simple React example that takes an app name and logs it to console when the Enter key press is detected. Everything working fine until I enter the app name in the input box and I press the Enter key, what I see then in the console log isn't the input value, but rather an "undefined" value. Here's the full JS Code:
"use strict";
var InputText = React.createClass({
render() {
return <div><p>Please input the app name you wish to access:</p></div>
}
});
var InputBox = React.createClass({
onKeyPress(e) {
if (e.key === 'Enter') {
console.log(this.props.value);
}
},
render() {
return <input type="text" onKeyPress={this.onKeyPress}></input>
}
});
var AppForm = React.createClass({
render() {
return <div class="appForm">
<InputText />
<InputBox />
</div>
}
});
var App = React.createClass({
render() {
return <AppForm />
}
});
ReactDOM.render(
<App />,
document.getElementById("container")
);
That's because you are not passing the value as a prop to your InputBox component.
You can get the value from the event
var InputBox = React.createClass({
onKeyPress(e) {
if (e.key === 'Enter') {
console.log('InputBox Value: ' + e.target.value);
}
},
render() {
return <input type="text" onKeyPress={this.onKeyPress}></input>
}
});
jsfiddle
Or store the value in the state and get it from there.
var InputBox = React.createClass({
onKeyPress(e) {
if (e.key === 'Enter') {
console.log('InputBox Value: ' + this.state.value);
}
},
render() {
return <input type="text" onKeyPress={this.onKeyPress} onChange={(e) => this.setState({value: e.target.value})}></input>
}
});
jsfiddle
you didnt pass any props into . You would pass props like this
there are no props passed anywhere in this app actually :)
But what you really want is the value from the input box. So in React you'd make a reference. As a quick and dirty example I have a global context object ctx={}
<input type="text" className="inputClass" style={inputStyles} ref={(c) => ctx._input = c} />
Now in my component I can refer to the value typed as
ctx._input.value
Console.log that and it should be all good.
Use ref to access the value of input box
"use strict";
var InputText = React.createClass({
render() {
return <div><p>Please input the app name you wish to access:</p></div>
}
});
var InputBox = React.createClass({
onKeyPress(e) {
if (e.key === 'Enter') {
console.log(this.refs.textbox.value);
}
},
render() {
return <input type="text" onKeyPress={this.onKeyPress} ref = 'textbox'></input>
}
});
var AppForm = React.createClass({
render() {
return <div class="appForm">
<InputText />
<InputBox />
</div>
}
});
var App = React.createClass({
render() {
return <AppForm />
}
});
ReactDOM.render(
<App />,
document.getElementById("container")
);
JSFIDDLE
Another way to obtain value will to use the event e as e.target.value. Props doesnt work because you are not actually passing props to the InputBox component.
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
I have following React.js application structure:
<App />
<BreadcrumbList>
<BreadcrumbItem />
<BreadcrumbList/>
<App />
The problem is, when I click on <BreadcrumbItem /> , I want to change a state in <App />
I used callback to pass props to <BreadcrumbList/> but that`s how far I got.
Is there any pattaren how to easily pass props up to compenent tree ?
How can I pass prop to <App />, without doing any callback chaining ?
If you are doing something simple then its often just better to pass the change in state up through the component hierarchy rather than create a store specifically for that purpose (whatever it may be). I would do the following:
BreadcrumbItem
var React = require('react/addons');
var BreadcrumbItem = React.createClass({
embiggenMenu: function() {
this.props.embiggenToggle();
},
render: function() {
return (
<div id="embiggen-sidemenu" onClick={this.embiggenMenu} />
);
}
});
module.exports = BreadcrumbItem ;
THEN pass it up to the parent through the BreadcrumbList component.....
<BreadcrumbItem embiggenToggle={this.props.embiggenToggle}>
... and UP to App, then use it to set the state....
var React = require('react/addons');
var App = React.createClass({
embiggenMenu: function() {
this.setState({
menuBig: !this.state.menuBig
});
},
render: function() {
return (
<div>
<BreadcrumbList embiggenToggle={this.embiggenMenu} />
</div>
)
}
});
module.exports = BreadcrumbItem;
This example toggles a simple boolean however you can pass up anything you like. I hope this helps.
I have not tested this but it was (quickly) ripped from a live working example.
EDIT:
As it was requested i'll expand upon the vague: "you can pass up anything".
If you were making a navigation menu based on an array and needed to pass up the selected item to a parent then you would do the following
var React = require('react/addons');
var ChildMenu = React.createClass({
getDefaultProps: function () {
return {
widgets : [
["MenuItem1"],
["MenuItem2"],
["MenuItem3"],
["MenuItem4"],
["MenuItem5"],
["MenuItem6"],
["MenuItem7"]
]
}
},
handleClick: function(i) {
console.log('You clicked: ' + this.props.widgets[i]);
this.props.onClick(this.props.widgets[i]);
},
render: function() {
return (
<nav>
<ul>
{this.props.widgets.map(function(item, i) {
var Label = item[0];
return (
<li
onClick={this.handleClick.bind(this, i)}
key={i}>
{Label}
</li>
);
}, this)}
</ul>
</nav>
);
}
});
module.exports = ChildMenu;
You would then do the following in the parent:
var React = require('react/addons');
var ChildMenuBar = require('./app/top-bar.jsx');
var ParentApp = React.createClass({
widgetSelectedClick: function(selection) {
//LOGGING
//console.log('THE APP LOGS: ' + selection);
//VARIABLE SETTING
var widgetName = selection[0];
//YOU CAN THEN USE THIS "selection"
//THIS SETS THE APP STATE
this.setState({
currentWidget: widgetName
});
},
render: function() {
return (
<ChildMenu onClick={this.widgetSelectedClick} />
);
}
});
module.exports = ParentApp;
I hope this helps. Thanks for the upvote.
If you use Flux pattern, you can have a AppStore which listen a BREADCRUMB_CLICK event. So when you click on a BreadCrumbItem, you can execute an action which dispatch BREADCRUMB_CLICK event. When AppStore handle the event, he inform App component which update your state.
For more informations:
Flux architecture
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.