ReactJS onChange event handler - javascript

I've got some confusion with React's event handler
I have a component like this, with handleChange handling onChange event:
var SearchBar = React.createClass({
getInitialState(){
return {word:''};
},
handleChange: function(event){
this.setState({word:event.target.value});
alert(this.state.word);
},
render: function () {
return (
<div style={{width:'100%',position:'0',backgroundColor:'darkOrange'}}>
<div className="header">
<h1>MOVIE</h1>
</div>
<div className="searchForm">
<input className="searchField" onChange={this.handleChange}
value={this.state.word} type="text" placeholder="Enter search term"/>
</div>
</div>
);
}
});
It does work, but not the way I expect. In textfield, when I type the first character, it alerts empty string, when the second character is typed, it alerts a string with only first character, and so on, with string length of n, it alerts the string with n-1 length
What did I do wrong here? How should I fix it?

Use like this,
Js:
this.setState({word:event.target.value}, function() {
alert(this.state.word)
});
Working Jsbin

I think it has something to do with state handling inside React.
I can come with two options to handle it.
Either:
handleChange: function(event) {
this.setState({word: event.target.value});
window.setTimeout(function() {
alert(this.state.word);
}.bind(this));
}
Or:
alertCurrentValue() {
alert(this.state.word);
},
render: function () {
this.alertCurrentValue();
return ( ... )
}

Praveen Raj's answer is definitely the right way to go. Here is the documentation I found from the official React website on why you should access this.state inside the callback rather than right after setState():
setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.

Related

Why isn't oncopy working with React but working with normal JavaScript code?

New to react js, can seem to understand why oncopy event is not working as intended.
HTML
<div id="container"></div>
<h1 oncopy="alert('copy1');">
I love react
</h1>
JS
var Hello = React.createClass({
render: function() {
return <div oncopy="alert('copy2');">I hate react</div>;
}
});
ReactDOM.render(
<Hello/>,
document.getElementById('container')
);
Fiddle : https://jsfiddle.net/yrshaikh/ejdcx517/
Pass the event with camel case and execute the statements with ES6 style arrow functions like
var Hello = React.createClass({
render: function() {
return <div onCopy={()=> alert('copy2')}>I hate react</div>;
}
});
JSFIDDLE
At first event props in react use capitalized letters (camel case). Second, you need to pass a function as an event handler in jsx. When you use "" it is considered to be string value. You need to pass function between curly braces {}:
onCopy={() => alert('copy2')}

why is react not re rendering on state change?

Cant work out what is going wrong.
I click a button, this sets the state and the setting of state, changes a key to be true and if that key is true, a different output should be rendered. here is the code:
click button call function:
<input type="submit" value="I can play" onClick={() => this.canPlay()}/>
runs this function:
canPlay: function() {
let name = this.props.value;
console.log(name, 'name');
let email = 'mark#mail';
this.submitUserResponseCanPlay(this.today(), name, email)
this.setState({thanks: true}) //SET STATE HERE
},
(thanks is set to false in getInitialState)
then in the render function:
render: function(){
let output;
if (this.state.thanks){
output = <Thanks />;
}
if the state is true, then render the new output. the ` part is a class that just has a return part inside the render function that looks like:
var Thanks = React.createClass({
render: function(){
return (
<div id="results" className="search-results">
Thanks, your answer has been recorded!
</div>
)
}
});
This does not show up though. any idea why??
the stranger thing is it is like this in another part of my file, and that part works. i.e. i click a submit button earlier and that changes a key/value pair from false to true and renders a new page layout. just not working here. maybe ive missed something small..
render: function(){
let output;
if (this.state.thanks){
output = <Thanks />;
}
This should be
render: function(){
if (this.state.thanks){
return <Thanks />
}
You always have to return something inside the render
I dont think you can set variables as jsx so if im wrong ignore this. BUT in this case it seems like youre probably trying to render a
{output}
somewhere in your code. instead replace that with
{this.state.thank ? <Thanks /> : null}

How to navigate via clickHandlers?

I just started learning React and I'm stuck in the following scenario.
There is an input field and on clicking the search button it takes the input value and redirect to /search/search-query/some-action
I have setup the path, defined the route to the correct view. And, I was able to do hit this path using href links. But my actual requirement is to have a button and take user to this path via onClick handler.
Searched a lot and found multiple (vague) solutions like, react-navigate-mixin etc. But I couldnt find any documentation around its usages.
Can anyone point me in the right direction?
I'm gonna make the assumption that you're not building a single page app and using something along the lines of React router. And that what you need to do is simply navigate to a url based on the input.
There are two main ways of doing depending on wether you want to:
Style an <a> as your button:
var Component = React.createClass({
getInitialState: function() { return {query: ''} },
queryChange: function(evt) {
this.setState({query: evt.target.value});
},
_buildLinkHref: function() {
return '/search/'+this.state.query+'/some-action';
},
render: function() {
return (
<div className="component-wrapper">
<input type="text" value={this.state.query} />
<a href={this._buildLinkHref()} className="button">
Search
</a>
</div>
);
}
});
This way you're keeping the query (value of the input) in the state. And whenever the input changes is automatically changes the href of the link.
Use a <button> and redirect programatically:
var Component = React.createClass({
getInitialState: function() { return {query: ''} },
queryChange: function(evt) {
this.setState({query: evt.target.value});
},
handleSearch: function() {
window.location = '/search/'+this.state.query+'/some-action';
},
render: function() {
return (
<div className="component-wrapper">
<input type="text" value={this.state.query} />
<button onClick={this.handleSearch()} className="button">
Search
</button>
</div>
);
}
});
This way you handle the redirect programatically by setting your desired location to window.location.
Adding on from the existing answer may need to bind your function like so:
constructor(props) {
super(props);
this.handleSearch = this.handleSearch.bind(this);
}

Using React LinkedStateMixin for text input doesn't re-render as expected

Here's the render function for one of my react components:
render: function() {
var valueLink = this.linkState.value;
var handleBlur = function(e) {
valueLink.requestChange(e.target.value);
};
return (
<input
type="text"
defaultValue={valueLink}
onBlur={handleBlur}
/>
);
}
I'm using backbone-react. After setting an attribute on the model, this component calls its render function. The backbone model gets set properly, but the input field doesn't render the value that was set on the model.
Basically when the render function gets called after the valueLink.value changes, the input field doesn't reflect this change.
I've tried using value instead of defaultValue but that makes it a controlled component.
I also don't want to use valueLink as that sets state for every key press whereas I only what to trigger that for onBlur.
Any ideas? (Please let me know if you need more info.)
From React docs
LinkedStateMixin adds a method to your React component called
linkState(). linkState() returns a ReactLink object which contains
the current value of the React state and a callback to change it.
In your example, instead of this.linkState.value, pass a state variable to linkState. Ex this.linkState('message')
var Component = React.createClass({
mixins: [React.addons.LinkedStateMixin],
getInitialState: function() {
return {message: 'Hello!'};
},
render: function () {
var valueLink = this.linkState('message');
var handleBlur = function(e) {
valueLink.requestChange(e.target.value);
};
return (
<div>
<input
type="text"
defaultValue={valueLink.value}
onBlur={handleBlur}
/>
<br />
{this.state.message}
</div>
);
}
});
React.render(<Component />, document.body);
http://jsfiddle.net/kirana/ne3qamq7/12/

How to reload input value in React / Javascript with Virtual DOM?

I have a problem with reload input value.
<input type="email" ref="email" id="email" value={this.props.handlingAgent.email}/>
after that i use
this.props.handlingAgent.email = "asd"
In debugger value of this.props.handlingAgent.email is actually asd, but in input is still old value. How to refresh that value without JQuery? Shouldn't it refresh automatically?
First, props are what's been passed onto you. View them as function parameters. The child really shouldn't go modify them since it breaks whatever assumption the parent has and makes your UI inconsistent.
Here, since the prop's passed onto you, you want to get a handler from parent that you can call to notify your change:
var App = React.createClass({
getInitialState: function() {
return {inputValue: ''};
},
handleChange: function(value) {
console.log('Value gotten back from the child: ' + value);
this.setState({
inputValue: value
});
},
render: function() {
return <Field onChange={this.handleChange} inputValue={this.state.inputValue} />;
}
});
var Field = React.createClass({
handleChange: function(event) {
// Make sure the parent passes the onChange to you as a prop
// See what I did here? It's not the actual DOM onChange. We're manually
// triggering it based on the real onChange fired by the `input`
this.props.onChange(event.target.value);
},
render: function() {
// I named the value prop `inputValue` to avoid confusion. But as you can
// see from `onChange`, it'd be nicer to name it just `value`
return <input value={this.props.inputValue} onChange={this.handleChange} />;
}
});
So yes, it does refresh "automatically", if you tell the parent to change. Instead of modifying what's been passed onto you, you use vanilla callbacks to the parent by passing it your new value. Then it flushes down the same value (or different, if fits) down to you.

Categories