React.js modify state of parent from button - javascript

I'm just digging into Reactjs. In my crude example I would like the delete button to remove an item from the items array. How would I do this from handleClick in the Btn component? Or what is the best way to handle this?
var data= {
"items": [
{
"title": "item1"
},
{
"title": "item2"
},
{
"title": "item3"
}
]
};
var Btn = React.createClass({
handleClick: function(e) {
console.log('clicked delete'+ this.props.id);
//how does delete button modify this.state.items in TodoApp?
},
render: function() {
return <button onClick={this.handleClick}>Delete</button>;
}
});
var TodoList = React.createClass({
render: function() {
var createItem = function(itemText, index) {
return <li key={index + itemText}>{itemText} <Btn id={index} /></li>;
};
return <div><ul>{this.props.items.map(createItem)}</ul></div>;
}
});
var TodoApp = React.createClass({
getInitialState: function() {
console.log("getInitialState");
return data;
},
onChange: function(e) {
this.setState({text: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
var nextItems = this.state.items.concat([this.state.text]);
var nextText = '';
this.setState({items: nextItems, text: nextText});
},
render: function() {
return (
<div>
<h3>TODO</h3>
<TodoList items={this.state.items} />
<form onSubmit={this.handleSubmit}>
<input onChange={this.onChange} value={this.state.text} />
<button>{'Add #' + (this.state.items.length + 1)}</button>
</form>
</div>
);
}
});
React.render(<TodoApp />, document.getElementById('container'));
JSFiddle example

The Flux way would be to update your data store and trigger a render of your app, f.ex:
var deleter = function(id) {
data.items.splice(id,1)
React.render(<TodoApp />,
document.getElementById('container'));
}
[...]
handleClick: function(e) {
deleter(this.props.id)
}
Demo: http://jsfiddle.net/s01f1a4a/

By sending a callback to your Btn component. Explained further in this answer.

Related

How to disable buttons on ReactJS properly?

I am learning ReactJS. I wrote a web app that should show an input text and a button 'Confirm', and when pressed it shows a second input text with a button 'Go back' which removes the new input. When the second one is showed, the first input and the first button are disabled.
However, my current script is not accepted. I'm having problems with passing functions as prop to the function FormRender and with indicating in the FormRender object itself the property "disabled" (it claims to have found "unexpected token").
Are there any better approaches?
function FormRender (props) {
return (
<div>
<input type = "text" placeholder = {this.props.holder} {this.props.disable} />
<button onClick = {this.props.Click()} {this.props.disable} > {this.state.value} </button>
</div>
);
};
var R = React.createClass ({
getInitialState: function () {
return { names: [], disable: false }
},
update: function () {
return this.state.disable ? "disabled" : "";
},
componentDidMount: function () {
var a = this.state.names;
a.push ( <FormRender holder = 'Name' value = 'Confirm' Click = {this.In}, disable: {this.update} /> );
this.setState ( { names: a } );
this.forceUpdate();
},
In: function () {
var a = this.state.names;
this.setState ( { disable: true } );
a.push ( <FormRender holder = 'Surname ' value = 'Back' Click = {this.Out} disable: "" /> );
this.setState ( { names: a } );
this.forceUpdate();
},
Out: function () {
var a = this.state.names;
this.setState ( { disable: false } );
a.splice(a.length-1,1);
this.setState ( { names: a } );
this.forceUpdate();
},
render: function () {
return (
<div>
{this.state.names}
</div>
);
}
});
I am not sure if it is what you want my example
function FormRender (props) {
return (
<div>
<input
type="text"
placeholder={props.holder}
disabled={props.disable()}
/>
<button
onClick={props.click}
disabled={props.disable()}
>
{props.value}
</button>
</div>
);
};
var R = React.createClass ({
getInitialState: function () {
return {names: [], disable: false}
},
update: function () {
return this.state.disable;
},
componentDidMount: function () {
var a = this.state.names;
var form = {
holder: 'Name',
value: 'Confirm',
click: this.In,
disable: this.update
};
a.push(form);
this.setState({names: a});
},
In: function () {
if (this.state.names.length > 1) {
return;
}
var a = this.state.names;
var form = {
holder: 'Surname',
value: 'Back',
click: this.Out,
disable: function () {
return false
}
}
this.setState({disable: true});
a.push(form);
this.setState({names: a});
},
Out: function () {
var a = this.state.names;
this.setState({disable: false});
a.splice(a.length-1,1);
this.setState({names: a});
},
render: function () {
return (
<div>
{this.state.names.map(function (el) {
return (<FormRender
holder={el.holder}
value={el.value}
click={el.click}
disable={el.disable}
/>);
})}
</div>
);
}
});
https://jsfiddle.net/69z2wepo/72509/
You have got many syntax errors in you code.
I recommend use linter :)

Cannot read property 'emit' of undefined error using React/Socket.IO

I'm trying to build a basic chat app using React and Socket.Io based on the React tutorial https://facebook.github.io/react/docs/tutorial.html but keep getting an error "Cannot read property 'emit' of undefined". It's probably something trivial that I overlooked but I can't figure it out.
The function that triggers the error is:
handleSubmit: function (e) {
e.preventDefault();
var author = this.state.author.trim();
var text = this.state.text.trim();
if (!text || !author) {
return;
}
this.props.onCommentSubmit({ author: author, text: text });
this.setState({ author: '', text: '' });
this.socket.emit('message', comment);
},
The full code is
import React, { Component, PropTypes } from 'react';
import ReactDom from 'react-dom';
import io from 'socket.io-client'
/********************************************************************************************************/
var CommentBox = React.createClass({
getInitialState: function () {
return { data: [] };
},
handleCommentSubmit: function (comment) {
this.setState({ data: [comment, ...this.state.data] });
},
componentDidMount: function (data) {
this.socket = io.connect();
this.socket.on('message', function (comment) {
this.setState({ data: [comment, ...this.state.data] });
});
},
render: function () {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
}
});
/********************************************************************************************************/
var CommentList = React.createClass({
render: function () {
var commentNodes = this.props.data.map(function (comment) {
return (
<Comment author={comment.author} key={comment.id}>{comment.text}</Comment>
);
});
return (
<div className="commentList">
{commentNodes}
</div>
);
}
});
/********************************************************************************************************/
var CommentForm = React.createClass({
getInitialState: function () {
return { author: '', text: '' };
},
handleAuthorChange: function (e) {
this.setState({ author: e.target.value });
},
handleTextChange: function (e) {
this.setState({ text: e.target.value });
},
handleSubmit: function (e) {
e.preventDefault();
var author = this.state.author.trim();
var text = this.state.text.trim();
if (!text || !author) {
return;
}
this.props.onCommentSubmit({ author: author, text: text });
this.setState({ author: '', text: '' });
this.socket.emit('message', comment);
},
render: function () {
return (
<div>
<form className='commentForm' onSubmit={this.handleSubmit}>
<input type='text' placeholder='Name' value={this.state.author} onChange={this.handleAuthorChange} />
<input type='text' placeholder='Enter Message' value={this.state.text} onChange={this.handleTextChange} />
<input type='submit' value='Post' />
</form>
</div>
);
}
});
/********************************************************************************************************/
var Comment = React.createClass({
render: function () {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
{this.props.children}
</div>
);
}
});
/********************************************************************************************************/
ReactDom.render(
<CommentBox />,
document.getElementById('container')
);
The call to this.socket.emit('message', comment) is at the wrong place neither this.socket nor comment is defined in your CommentForm Component.
You have to call this.socket.emit('message', comment) in the handleCommentSubmit Method in the CommentBox Component. (Line 14 in the second code example)

React - Load Initial List via AJAX

I'm starting to learn react. There's an excellent example in the official docs about loading data initially via AJAX:
var UserGist = React.createClass({
getInitialState: function() {
return {
username: '',
lastGistUrl: ''
};
},
componentDidMount: function() {
this.serverRequest = $.get(this.props.source, function (result) {
var lastGist = result[0];
this.setState({
username: lastGist.owner.login,
lastGistUrl: lastGist.html_url
});
}.bind(this));
},
componentWillUnmount: function() {
this.serverRequest.abort();
},
render: function() {
return (
<div>
{this.state.username}'s last gist is
<a href={this.state.lastGistUrl}>here</a>.
</div>
);
}
});
ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists" />,
mountNode
);
The code above gets the latest gist of a specific user from GitHub.
What is the best way in React to go about outputting a list of the last 10 gists of the specific user?
How would you modify the code sample above?
var UserGist = React.createClass({
getInitialState: function() {
return {
gists: []
};
},
componentDidMount: function() {
this.serverRequest = $.get(this.props.source, function (result) {
this.setState({
gists: result
});
}.bind(this));
},
componentWillUnmount: function() {
this.serverRequest.abort();
},
render: function() {
return <div>
{this.state.gists.map(function(gist){
return <div key={gist.id}>{gist.owner.login}</div>
})}
<div>;
}
});
ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists" />,
mountNode
);

Does ReactJS have a binding for input fields?

I have a (reasonably complex) form in react that in a pared-down form looks like this:
var MyForm = React.createClass({
init: { data: { "MyValue" : "initial value" } },
getInitialState: function() {
return this.init;
},
componentDidMount: function () {
this.setState({data: this.props.basedata });
},
save: function (ev) {
ev.preventDefault();
var d = this.state.data;
console.log(ev, d, d.MyValue)
},
render: function () {
if(this.state.data === null){ return; }
var d = this.state.data;
return (
<div>
<form>
<input type="text" placeholder="Enter Value" defaultValue={d.MyValue} />
<button onClick={this.save}>Save</button>
</form>
<div>{d.MyValue}</div>
</div>);
}
});
var dataObject = { "MyValue" : "external value" }
ReactDOM.render( <MyForm basedata={dataObject} />, document.getElementById('container'));
(available as a jsfiddle here: https://jsfiddle.net/achesser/d8veuvnh/1/)
Does react have a "built in" way of ensuring that the value of d.MyValue is updated to the value within the input box at the time I click "save"? or do I have to write an OnChange handler for each input?
I've update the jsfiddle , I bound {d.MyValue} to the html value property in stead of the defaultValue:
var Hello = React.createClass({
init: { data: { "MyValue" : "initial value" } },
getInitialState: function() {
return this.init;
},
componentDidMount: function () {
this.setState({data: this.props.basedata });
},
save: function (ev) {
ev.preventDefault();
var d = this.state.data;
console.log(ev, d, d.MyValue)
},
render: function () {
if(this.state.data === null){ return; }
var d = this.state.data;
return (
<div>
<form>
<input type="text" placeholder="Enter Value" value={d.MyValue} />
<button onClick={this.save}>Save</button>
</form>
<div>{d.MyValue}</div>
</div>);
}
});
var dataObject = { "MyValue" : "external value" }
ReactDOM.render( <Hello basedata={dataObject} />, document.getElementById('container'));

How to listen on events on react with plain javascript?

If you go here: http://facebook.github.io/react/index.html you will find tutorials in jsx but how do I use only js?
/** #jsx React.DOM */
var TodoList = React.createClass({
render: function() {
var createItem = function(itemText) {
return <li>{itemText}</li>;
};
return <ul>{this.props.items.map(createItem)}</ul>;
}
});
var TodoApp = React.createClass({
getInitialState: function() {
return {items: [], text: ''};
},
onChange: function(e) {
this.setState({text: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
var nextItems = this.state.items.concat([this.state.text]);
var nextText = '';
this.setState({items: nextItems, text: nextText});
},
render: function() {
return (
<div>
<h3>TODO</h3>
<TodoList items={this.state.items} />
<form onSubmit={this.handleSubmit}>
<input onChange={this.onChange} value={this.state.text} />
<button>{'Add #' + (this.state.items.length + 1)}</button>
</form>
</div>
);
}
});
React.renderComponent(<TodoApp />, mountNode);
For example the above code is using a listener, how do I do that in plain javascript?
thanks
Just found this: http://facebook.github.io/react/jsx-compiler.html
/** #jsx React.DOM */
var TodoList = React.createClass({displayName: 'TodoList',
render: function() {
var createItem = function(itemText) {
return React.DOM.li(null, itemText);
};
return React.DOM.ul(null, this.props.items.map(createItem));
}
});
var TodoApp = React.createClass({displayName: 'TodoApp',
getInitialState: function() {
return {items: [], text: ''};
},
onChange: function(e) {
this.setState({text: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
var nextItems = this.state.items.concat([this.state.text]);
var nextText = '';
this.setState({items: nextItems, text: nextText});
},
render: function() {
return (
React.DOM.div(null,
React.DOM.h3(null, "TODO"),
TodoList( {items:this.state.items} ),
React.DOM.form( {onSubmit:this.handleSubmit},
React.DOM.input( {onChange:this.onChange, value:this.state.text} ),
React.DOM.button(null, 'Add #' + (this.state.items.length + 1))
)
)
);
}
});
React.renderComponent(TodoApp(null ), mountNode);

Categories