I'm doing the tutorial on the React.js website. Here is my code:
<html>
<head>
<title>Hello React</title>
<script src="http://fb.me/react-0.8.0.js"></script>
<script src="http://fb.me/JSXTransformer-0.8.0.js"></script>
<script src="http://code.jquery.com/jquery-1.10.0.min.js"></script>
</head>
<body>
<div id="content"></div>
<script type="text/jsx">
/**
* #jsx React.DOM
*/
// The above declaration must remain intact at the top of the script.
// Your code here
var commentsData = [
{author: "Pete Hunt", text: "This is one comment"},
{author: "Jordan Walke", text: "This is *another* comment"}
];
var CommmentBox = React.createClass({
getInitialState: function() {
return {data: []};
},
componentWillMount: function() {
this.loadComments();
},
render: function() {
return (
<div className='commmentBox'>
<h1>Comments</h1>
<CommentList data={this.state.data} />
<br />
<CommentForm onCommentSubmit={this.handleCommentSubmit} />
</div>
);
},
handleCommentSubmit: function(comment) {
commentsData.push(comment);
this.loadComments();
},
loadComments: function() {
console.log(commentsData.length);
this.setState({data: commentsData});
}
});
var CommentList = React.createClass({
render: function() {
var commentNodes = this.props.data.map(function(comment) {
return <Comment author={comment.author} text={comment.text} />;
});
return (
<div className='commentList'>
{commentNodes}
</div>
);
}
});
var CommentForm = React.createClass({
render: function() {
return (
<form className='commentForm' onSubmit='handleSubmit'>
<input type='text' placeholder='Your name' ref='author'/>
<input type='text' placeholder='Your comment' ref='text'/>
<input type='submit' value='Post' />
</form>
);
},
handleSubmit: function() {
var author = this.refs.author.getDOMNode().value.trim();
var text = this.refs.text.getDOMNode().value.trim();
this.props.onCommentSubmit({author: author, text: text});
this.refs.author.getDOMNode().value = '';
this.refs.text.getDOMNode().value = '';
return false;
}
});
var Comment = React.createClass({
render: function() {
return(
<div className='comment'>
<br />
<h3 className='commentAuthor'>
{this.props.author} wrote:
</h3>
<h3 className='commentText'>
{this.props.text}
</h3>
</div>
);
}
});
React.renderComponent(
<CommmentBox />,
document.getElementById('content')
);
</script>
</body>
</html>
When I add comments, they don't show up in the comments list. I'm logging the length of the comment array to the console, and it never changes. What am I doing wrong?
You need to do this because you were using a string in onSubmit event.
<form className='commentForm' onSubmit={this.handleSubmit}>
You had this in your sample code:
<form className='commentForm' onSubmit='handleSubmit'>
Your code caused a Uncaught TypeError: string is not a function error. Because of that error it was not hitting the handleSubmit function and also caused the browser to reload.
Related
I am creating one react form which looks like wizard type means on click of next button, it will load another component.
To do with this, i am using javascript iterators. I am updating state based on what iterator returns but i dont understand its not updating state of the component.
Code:
console.clear();
var Email = React.createClass({
render: function() {
return (
<div className="form-group">
<label className="control-label">Email:</label>
<input className="form-control" />
</div>
);
}
});
var Password = React.createClass({
render: function() {
return (
<div className="form-group">
<label className="control-label">Password:</label>
<input className="form-control" />
</div>
);
}
});
var Contact = React.createClass({
render: function() {
return (
<div className="form-group">
<label className="control-label">Contact:</label>
<input className="form-control" />
</div>
);
}
});
var Form = React.createClass({
getInitialState: function(){
this.fit = this.flowIterator([<Email />,<Password />,<Contact />]);
return {
view: this.fit.next(),
submitBtnText: "Next"
};
},
flowIterator: function(array){
var nextIndex = 0;
return {
next: function(){
console.log("nextIndex=",nextIndex);
console.log("array.length-1=",array.length-1);
console.log("nextIndex == array.length-1 =",nextIndex == array.length-1);
return nextIndex == array.length-1 ?
{value: array[nextIndex++], done: true} :
{value: array[nextIndex++], done: false};
}
}
},
onFormSubmit: function(e){
this.setState({
onChange: this.onStateChange()
});
e.preventDefault();
},
onStateChange: function(){
console.log("State change event fired!!");
this.setState({
view: this.fit.next(),
submitBtnText: "Next"
});
console.log("this.state.view.done=",this.state.view.done);
if(this.state.view.done){
this.setState({
submitBtnText: "Login"
});
}
},
render: function() {
return (
<form className="form-horizontal col-xs-6" onSubmit={this.onFormSubmit}>
{this.state.view.value}
<div className="form-group">
<button className="btn btn-success pull-right">{this.state.submitBtnText}</button>
</div>
</form>
);
}
});
ReactDOM.render(
<Form />,
document.getElementById('container')
);
check the code in jsfiddle
Thank you...
I'm trying to work through the React Tutorial and have run into a stumbling block. I have the following HTML
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="shortcut icon" href="./src/favicon.ico" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/css/materialize.min.css" />
<script src="https://npmcdn.com/react#15.3.1/dist/react.js"></script>
<script src="https://npmcdn.com/react-dom#15.3.1/dist/react-dom.js"></script>
<script src="https://npmcdn.com/babel-core#5.8.38/browser.min.js"></script>
<script src="https://npmcdn.com/jquery#3.1.0/dist/jquery.min.js"></script>
<script src="https://npmcdn.com/remarkable#1.6.2/dist/remarkable.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/js/materialize.min.js"></script>
<script type="text/babel" src="src/index.js"></script>
<title>React App</title>
</head>
<body>
<div class="container">
<div class="row">
<div id="sidebar" class="col s3">
</div>
<div id="content" class="col s9">
</div>
</div>
</div>
<script type="text/babel">
</script>
</body>
</html>
With the following javascript file.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
var data = [
{ id: 1, author: "Pete Hunt", text: "This is the 1st comment" },
{ id: 2, author: "Jordan Walke", text: "This is *the 3rd* comment." },
{ id: 3, author: "John Doe", text: "This comment is stupid." }
];
var CommentBox = React.createClass({
getInitialState: function() {
return { data: [] };
},
componentDidMount: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
cache: false,
success: function(data) {
this.setState({ data: data });
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm />
</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({
render: function() {
return (
<div className="commentForm">
I'm a Form.
</div>
);
}
});
var Comment = React.createClass({
rawMarkup: function() {
var markdown = new Remarkable();
var rawMarkup = markdown.render(this.props.children.toString());
return { __html: rawMarkup };
},
render: function() {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
<span dangerouslySetInnerHTML={this.rawMarkup()} />
</div>
);
}
});
ReactDOM.render(
<CommentBox data={data} />,
document.getElementById('content')
);
I'm using the content created from the Create React App NPM module. When I run the app, I'm told:
Remarkable isn't defined
$ is not defined
Both JQuery and Remarkable are included in my HTML file, and I made sure to put them before my index.js script. Why is it that the app can't find the Types? Is this a React issue, or a Node,js issue? I'm a bit new to web-dev so I'm not sure which component is at fault here or what i'm doing wrong.
Seems like your scripts are loading asynchronously. Waiting for all your scripts to be loadded with jQuery...
(function($){$(function(){
// your react app code here...
})})(jQuery);
So I am learning react.js, and I am developing a quick search engine using the GitHub API of users.
The API side of the project works fine (I have tested by manually entering names into the area)
Its the search build in react that is not working.
(FYI: I am using Plunker which has react support)
script.jsx
var Card = React.createClass({
getInitialState: function(){
return{};
},
componentDidMount: function(){
var component = this;
$.get("https://api.github.com/users/" + this.props.login, function(data){
component.setState(data);
});
},
render: function(){
return(
<div>
<img src={this.state.avatar_url} width="100"/>
<h3>{this.state.name}</h3>
<hr/>
</div>
);
}
});
var Form = React.createClass({
handleSubmit: function(e){
e.preventDefault();
var loginInput = React.findDOMNode(this.refs.login);
this.props.addCard(loginInput.value);
loginInput.value = '';
},
render: function(){
return(
<form onSubmit={this.handleSubmit}>
<input placeholder="Enter Github Name" ref="login"/>
<button>Search</button>
</form>
);
}
});
var Main = React.createClass({
getInitialState: function(){
return {logins: []};
},
addCard: function(loginToAdd){
this.setState({logins: this.state.logins.concat(loginToAdd)});
},
render: function() {
var cards = this.state.logins.map(function(login){
return (<Card login={login} />);
});
return(
<div>
<Form addCard={this.addCard} />
{cards}
</div>
)
}
});
ReactDOM.render(<Main />, document.getElementById("root"));
The problem was (if you check console), that you had a duplicate script tag in the <head> which you didn't need. And also, you were doing React.findDOMNode instead of ReactDOM.findDOMNode
Line 25 of your JSX file:
var loginInput = ReactDOM.findDOMNode(this.refs.login);
That said, you don't need to do ReactDOM.findDOMNode. You can just use this.refs.login
I am trying to make a todo app in react. But it keeps double posting. I made an edit function and after that it keeps double posting. I have followed the example of the guide. But I can not find the error.
<!DOCTYPE html>
<html>
<head>
<title>EASY SHIT</title>
<meta charset="utf-8">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<script src="../../build/react.js"></script>
<script src="../../build/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script>
<style>
body{
margin-top:30px;
}
a.delete{
color: red;
}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-12">
<div id="app"></div>
</div>
</div>
</div>
<script type="text/babel">
var App = React.createClass({
getInitialState: function (){
return{
text: '',
isEdit: 0,
todos:[
{
id: 1,
text: 'meeting at work'
},
{
id: 2,
text: 'Walk the dog'
},
{
id: 3,
text: 'Eat candy'
}
]
}
},
render: function(){
return(
<div>
<TodoForm
{...this.state}
changeText={this.handleChangeText}
onTodoUpdate={this.handleTodoUpdate}
onTodoAdd={this.handleTodoAdd} />
<TodoList
{...this.state}
editTodo={this.handleTodoEdit}
deleteTodo={this.handleTodoDelete}/>
</div>
)
},
handleTodoAdd: function(text){
var newTodo = {
id: this.state.todos.length + 1,
text: text
}
this.setState({todos: this.state.todos.concat(newTodo)});
},
handleTodoDelete: function(todo){
var todos = this.state.todos;
for(var i = 0;i <todos.length; i++) {
if(todos[i].id == todo.id){
todos.splice(i, 1);
}
}
this.setState({todos: todos});
},
handleTodoEdit: function(todo){
this.setState({
text: todo.text,
isEdit: todo.id
});
},
handleChangeText: function(text){
this.setState({text: text});
},
handleTodoUpdate: function(todo){
var todos = this.state.todos;
for(var i = 0;i <todos.length; i++) {
if(todos[i].id == todo.id){
todos.splice(i, 1);
}
}
todos.push(todo);
this.setState({todos: todos});
}
});
var TodoForm = React.createClass({
render: function(){
return(
<div>
<form onSubmit={this.onSubmit}>
<div className="form-group">
<label>Todo text</label>
<input type="text" ref="text" value={this.props.text} onChange={this.onChange} className="form-control" />
</div>
</form>
</div>
)
},
onChange: function(e){
this.props.changeText(e.target.value);
},
onSubmit: function(e){
e.preventDefault();
var text = this.refs.text.value.trim();
if(!text){
alert('Please enter something');
return;
}
if(this.props.isEdit){
var updatedTodo = {
id:this.props.isEdit,
text: text
}
this.props.onTodoUpdate(updatedTodo);
} else {
this.props.onTodoAdd(text);
}
this.props.onTodoAdd(text);
this.refs.text.value= '';
}
});
var TodoList = React.createClass({
render: function(){
return(
<ul className="list-group">
{
this.props.todos.map(todo => {
return <li className="list-group-item" todo={todo} key ={todo.id}>
<span onClick={this.editTodo.bind(this, todo)}> {todo.text}</span> <a onClick={this.OnDelete.bind(this, todo)}className="delete" href="#">x</a></li>
})
}
</ul>
)
},
OnDelete: function(todo){
this.props.deleteTodo(todo);
},
editTodo: function(todo){
this.props.editTodo(todo);
}
});
ReactDOM.render(
<App />,
document.getElementById('app')
);
</script>
</body>
</html>
It looks to me like you aren't tracking whether you are editing an existing item or adding a new one.
If you're editing, then you need to track which one, then replace it or update it in your state, otherwise append to the list. You're just appending, so your app always thinks a new one is being added and hence it looks like it's double posting, but it is actually adding a brand new item that happens to have updated text.
The other option is to call delete and then edit, which will have the same effect.
Html:
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>React Tutorial</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.6/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.6/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src='https://cdn.firebase.com/js/client/2.2.1/firebase.js'></script>
</head>
<body>
<div id="content">
<!--<h1>Comments</h1>-->
<!--<ul id="comments-list"></ul>-->
</div>
<!--<div id="input">-->
<!--<input type="text" placeholder="Author" id="author-field">-->
<!--<input type="text" placeholder="Comment" id="comment-field">-->
<!--</div>-->
<script type="text/babel" src="example.js"></script>
</body>
</html>
Js:
var Comment = React.createClass({
render: function() {
return (
<div className="comment">
<h4 className="commentAuthor">
{this.props.author}
</h4>
<p>{this.props.comment}</p>
</div>
);
}
});
var CommentBox = React.createClass({
getInitialState: function () {
return {data: [], author: "", comment: ""}
},
componentWillMount: function() {
this.commentsDB = new Firebase('https://burning-fire-9280.firebaseio.com/comments');
this.commentsDB.on("child_added", function(snap) {
var nextData = this.state.data.concat(snap.val());
this.setState(
{data: nextData, comment: ""}
)
}).bind(this)
},
onAuthorChange: function(e) {
e.preventDefault();
this.setState({
author: e.target.value
});
},
onCommentChange: function (e) {
e.preventDefault();
this.setState({
comment: e.target.value
});
},
handleSubmit: function (e) {
this.commentsDB.push({
author: this.state.author, comment: this.state.comment, date: getEpoch()
})
},
render: function() {
return (
<div className="commentBox">
<h1>Comments</h1>
<CommentList data={this.state.data} />
<CommentForm onAuthorChange={this.onAuthorChange} onCommentChange={this.onCommentChange} state={this.state}/>
</div>
);
}
});
var CommentList = React.createClass({
render: function() {
var commentNodes = this.props.data.map(function(entry) {
return (
<Comment author={entry.author} comment={entry.comment}>
</Comment>
);
});
return (
<div className="commentList">
{commentNodes}
</div>
);
}
});
var CommentForm = React.createClass({
render: function() {
return (
<form onSubmit={this.props.handleSubmit}>
<input id="author-field" onChange={this.props.onAuthorChange} value={this.props.state.author} />
<input id="comment-field" onChange={this.props.onCommentChange} value={this.props.state.comment} />
</form>
);
}
});
ReactDOM.render(
<CommentBox />,
document.getElementById('content')
);
Error msg from chrome:
Uncaught TypeError: Cannot read property 'state' of null(anonymous function) # example.js:25(anonymous function) # firebase.js:52Ab # firebase.js:47wb # firebase.js:22xb # firebase.js:21h.Cd # firebase.js:194h.Bd # firebase.js:182Zg.Bd # firebase.js:174(anonymous function) # firebase.js:172Ug # firebase.js:166ua.onmessage # firebase.js:165
firebase.js:40 FIREBASE WARNING: Exception was thrown by user callback. TypeError: Cannot read property 'state' of null
at eval (eval at <anonymous> (https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js:4:28099), <anonymous>:35:26)
at https://cdn.firebase.com/js/client/2.2.1/firebase.js:52:375
at Ab (https://cdn.firebase.com/js/client/2.2.1/firebase.js:47:165)
at wb (https://cdn.firebase.com/js/client/2.2.1/firebase.js:22:216)
at xb (https://cdn.firebase.com/js/client/2.2.1/firebase.js:21:1261)
at Bh.h.Cd (https://cdn.firebase.com/js/client/2.2.1/firebase.js:194:472)
at kh.h.Bd (https://cdn.firebase.com/js/client/2.2.1/firebase.js:182:251)
at Zg.Bd (https://cdn.firebase.com/js/client/2.2.1/firebase.js:174:364)
at Rg.hg (https://cdn.firebase.com/js/client/2.2.1/firebase.js:172:281)
at Ug (https://cdn.firebase.com/js/client/2.2.1/firebase.js:166:464)
It seems to be complaining that the state of the CommentBox node is null, but the I have set the initial state to be {data: [], author: "", comment: ""}, haven't I?
It seems a little bit different. It says "cannot read property state of null" like if this is null (that is quite odd!!).
What is the line 25?
Probably the bind call is in the wrong place:
componentWillMount: function() {
this.commentsDB = new Firebase('https://burning-fire-9280.firebaseio.com/comments');
this.commentsDB.on("child_added", function(snap) {
var nextData = this.state.data.concat(snap.val());
this.setState(
{data: nextData, comment: ""}
)
}.bind(this)) // *** must be attached to the callback inside the parenthesis.
},