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.
Related
I am trying to grab data only when user stops typing and remove cursor from input e.g onBlur along with when Up and down keys are pressed in React
var ExampleForm = React.createClass({
getInitialState: function () {
return {lastName: 1}
},
onsChange: function(event) {
this.setState({lastName: event.target.value});
},
render: function() {
return (<div>
<input name='lastName'
value={this.state.lastName}
type={"number"}
onChange={this.onsChange.bind(this)}/>
</div>
);
}
});
ReactDOM.render(
<ExampleForm/>,
document.getElementById('view'));
for remove cursor you have to use setTimeout. Do like this...
onsChange(event) {
this.setState({lastName: event.target.value});
var currentTarget = event.target;
setTimeout(function(){
currentTarget.blur();
}, 3000);
}
render() {
return (
<div>
<input name='lastName'
value={this.state.lastName}
type={"number"}
onChange={this.onsChange.bind(this)}/>
</div>
);
}
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'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 below a working component that allows for a checkbox all and checkboxes. It works perfectly. However I hate the idea that I'm stuck carrying all of this code around every time I want to use this feature. I'm looking for a way within react to make this modular? Is this
It doesn't modularize the entire functionality of the "input checked all" functionality in one place. I have to move the getInitialState variables and changeHandlers with each usage.
I think of it like if the "input checkbox all" functionally was native within HTML, how would we use it? We would need only supply the attributes to the elements and they would reference each other and all of the handlers would occur under the hood, it would be simple to use. My goal with this example is to have HTML level simplicity. The code I show above doesn't achieve that because it's tied down to function handlers and state initializers. Does react provide a way of abstracting this?
Below is my desired API for this component.
Here's the working example.
The main problems are:
The component functionality is indifferent to the parent, meaning the paren't doesn't need to store the information for the handlers and state.
The code currently manually tracks state for each checkbox, meaning there's no way to dynamically find how many of an a checkbox is in the DOM without stating it.
Overall modularity and ease-of use.
Here's the code:
var InputCheckbox = React.createClass({
getDefaultProps: function () {
return {
checked: false
}
},
render: function () {
return (
<input
checked={this.props.checked}
type='checkbox'
{...this.props}/>
)
}
})
var Test = React.createClass({
getInitialState: function () {
return {
checked: [false, false, false]
}
},
selectAll: function (event) {
// Set all checked states to true
this.setState({
checked: this.state.checked.map(function () {
return event.target.checked
})
})
},
handleChange: function (index, event) {
var checked = this.state.checked
checked[index] = event.target.checked
this.setState({
checked: checked
})
},
render: function () {
var isAllChecked = this.state.checked.filter(function (c) {
return c
}).length === this.state.checked.length
return (
<div>
Select All:
<InputCheckbox onChange={this.selectAll} checked={isAllChecked}/>
<br/>
<InputCheckbox checked={this.state.checked[0]} onChange={this.handleChange.bind(this, 0)}/>
<br/>
<InputCheckbox checked={this.state.checked[1]} onChange={this.handleChange.bind(this, 1)}/>
<br/>
<InputCheckbox checked={this.state.checked[2]} onChange={this.handleChange.bind(this, 2)}/>
<br/>
</div>
)
}
})
React.render(<Test/>, document.body)
Ideally I can just use it like this:
var Checkbox = require('./Checkbox')
var Test = React.createClass({
render: function () {
return (
<div>
<Checkbox id="alpha"/>
<Checkbox htmlFor="alpha"/>
<Checkbox htmlFor="alpha"/>
<Checkbox htmlFor="alpha"/>
</div>
)
}
})
The following example is in the right general direction I think, the general idea is to introduce a wrapper component for the related boxes, and then walk through the children in that component to tie them together.
var CheckAll = React.createClass({
render() {
return <input type="checkbox" {...this.props} />
}
});
var Checkbox = React.createClass({
render() {
return <input type="checkbox" {...this.props} />
}
});
var CheckboxGroup = React.createClass({
setAll(to) {
var result = {};
Object.keys(this.props.boxes).forEach(k => result[k] = to)
this.props.onChange(result);
},
setOne(name, to) {
var result = {};
Object.keys(this.props.boxes).forEach(k => result[k] = this.props.boxes[k])
result[name] = to;
this.props.onChange(result);
},
enrichChild(child) {
var boxes = this.props.boxes;
var all = Object.keys(boxes).every(k => boxes[k]);
if (child.type == CheckAll) {
return React.cloneElement(child, { checked: all,
onChange: () => this.setAll(!all)
});
} else if (child.type == Checkbox) {
var name = child.props.name;
return React.cloneElement(child, { checked: !!boxes[name],
onChange: ({target}) => this.setOne(name, target.checked)
});
} else {
return child;
}
},
render() {
return (
<div>
{React.Children.map(this.props.children, this.enrichChild)}
</div>
)
}
});
var Test = React.createClass({
getInitialState: function () {
return {
boxes: {
a: true,
b: false,
c: false,
}
}
},
render: function () {
return (
<div>
<CheckboxGroup
boxes={this.state.boxes}
onChange={boxes => this.setState({boxes})}
>
<CheckAll />
<Checkbox name="a" />
<Checkbox name="b" />
<Checkbox name="c" />
</CheckboxGroup>
</div>
)
}
})
React.render(<Test/>, document.body)
Here's a jsbin - https://jsbin.com/zomuxolevo/1/edit?js,output
To allow for more flexibility with the children, you'd need to recursively walk them using something like this gist https://gist.github.com/dandelany/1ff06f4fa1f8d6f89c5e
var RecursiveChildComponent = React.createClass({
render() {
return <div>
{this.recursiveCloneChildren(this.props.children)}
</div>
},
recursiveCloneChildren(children) {
return React.Children.map(children, child => {
if(!_.isObject(child)) return child;
var childProps = {someNew: "propToAdd"};
childProps.children = this.recursiveCloneChildren(child.props.children);
return React.cloneElement(child, childProps);
})
}
})
I hacked this together using some jQuery, and lodash.
Here's the example running.
Note, this example goes into the DOM to get the data needed. None of the state of these checkboxes are stored by the component. As far as I can tell there is no true "React" way to do this. (I am very open to suggestion.)
var Checkbox = React.createClass({
componentDidMount: function () {
var component = React.findDOMNode(this)
var $component = $(component)
if ($component.attr('id')) {
var selector = 'input'
selector += '[data-component=Checkbox]'
selector += '[for=' + $component.attr('id') + ']'
var $forComponents = $(selector)
$component.on('change', function () {
var value = $component.prop('checked')
$forComponents.each(function () {
$forComponent = $(this)
$forComponent.prop('checked', value)
})
})
$forComponents.on('change', function () {
var values = $forComponents.map(function () {
var $forComponent = $(this)
var value = $forComponent.prop('checked')
return value
})
var simple = _.chain(values).unique().value()
if (simple.length === 1 && simple[0] === true) {
$component.prop('checked', true)
} else {
$component.prop('checked', false)
}
})
}
},
render: function () {
return (
<input
type='checkbox'
data-component='Checkbox'
{...this.props}/>
)
}
})
var Test = React.createClass({
render: function () {
return (
<div>
Select All: <Checkbox id='alpha'/><br/>
<Checkbox htmlFor='alpha'/><br/>
<Checkbox htmlFor='alpha'/><br/>
<Checkbox htmlFor='alpha' defaultChecked/><br/>
<Checkbox htmlFor='alpha'/><br/>
<Checkbox htmlFor='alpha'/><br/>
</div>
)
}
})
React.render(<Test/>, document.body)
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')
);