I am new in react and I'm learning on official website with tutorial help.
So, I have structure in my app:
-js
-notes.js
-comment.json
index.html
notes.js have next code:
var CommentBox = React.createClass({
loadCommentsFromServer: 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)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function () {
this.loadCommentsFromServer();
setInterval(this.loadCommentsFromServer, this.props.pollInterval);
},
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">
Hello, world! I am a CommentForm.
</div>
);
}
});
var Comment = React.createClass({
render: function () {
return (
<div className="comment">
<h2 className="commentAuthor">
{this.props.author}
</h2>
<p>
{this.props.children}
</p>
</div>
);
}
});
ReactDOM.render(
<CommentBox url="comment.json" pollInterval={2000} />,
document.getElementById('content')
);
Here my file data "comment.json":
[
{"id": "1", "author": "Pete Hunt", "text": "This is one comment"},
{"id": "2", "author": "Jordan Walke", "text": "This is *another* comment"}
]
But it doesn't work and in console I have next message:
jquery.js:9392 GET http://helper.com/views/com.json?_=1471986105038 404 (Not Found)
and another one:
notes.js:22 com.json error Not Found
Maybe I write wrong url parametr in:
<CommentBox url="comment.json" pollInterval={2000} />
Can anybody help me?
Related
I'm doing a react app and id I'd like to know how to think multipages websites. Actually i'im I'm doing a course searcher,i searcher; I use routie to render the different components that renders render the page. The problem is that they arent aren't related by hierarchy, so the ajax data isn't accessible to the component that renders the result.I've I've tried vainly to use a js var data but doesnt var data but that doesn't work too either.Ive read https://facebook.github.io/react/tips/communicate-between-components.html
but i don't see what to do with own event system. If someone could illustrate the last paragraph of this doc it is great for all the people that are in this case.
var data = {};
var CourseSearcher = React.createClass({
getInitialState: function(){
return {
return { places: '',
branch: 0,
dayOfMonth: '',
timeStart: '',
timeEnd: '',
data: []};
},;
},
handlePlacesChange: function(e){
this.setState({places: e.target.value});
},
handleBranchChange: function(e){
this.setState({branch: e.target.value});
},
handleDayOfMonthChange: function(e){
this.setState({dayOfMonth: e.target.value});
},
handleTimeStartChange: function(e){
this.setState({timeStart: e.target.value});
},
handleTimeEndChange: function(e){
this.setState({timeEnd: e.target.value});
},
handleSubmit: function(e){
// stop the default browser action
e.preventDefault();
// Do an ajax post
$.ajax({
url:'php/results.php',
dataType: 'json',
type: 'GET',
data: {
data: {places: this.state.places,
branch:this.state.branch,
dayOfMonth:this.state.dayOfMonth,
timeStart:this.state.timeStart,
timeEnd:this.state.timeEnd},
},
success: function(data){
this.setState({data: data});
data = this.state.data;
routie('results');
}.bind(this),
error: function (xhr,status,err){
console.error('php/results.php',status,err.toString());
}.bind(this)
});
},
render: function(){
return(
<div>
<form method="get" onSubmit={this.handleSubmit}>
<label>Où?</label>
<input
type="text"
placeholder="Lieux"
value={this.state.places}
onChange={this.handlePlacesChange}
/>
<label>Quoi?</label>
<select value={this.state.branch} onChange={this.handleBranchChange}>
<option>Matière</option>
<option>Français</option>
<option>Anglais</option>
</select>
<label>Quand ?</label>
<input
type="date"
value={this.state.dayOfMonth}
onChange={this.handleDayOfMonthChange}
/>
<input
type="time"
value={this.state.timeStart}
onChange={this.handleTimeStartChange}
/> -
<input
type="time"
value={this.state.timeEnd}
onChange={this.handleTimeEndChange}/>
<button type="submit">Go!</button>
</form>
</div>
);
}
});
console.log(data);
var ResultList = React.createClass({
render: function() {
console.log(data);
return(
<h1>Hello</h1>);
}
);
}
});
var ResultBox = React.createClass({
render: function() {
return (
<div>
<h4>{}</h4>
</div>
);
}
});
routie({
'':function() {
React.render(<CourseSearcher />,
document.getElementById('content'));
},
'results': function() {
React.render(
React.render(<ResultList results={data} />,
document.getElementById('content'));
}
});
Done well with react router ;)
I've done it with react router where components are related to some dedicated urls
I have three separate files.
Nav.js
var NavItem = React.createClass({
render: function() {
return (
<li>{this.props.name}</li>
);
}
});
var NavList = React.createClass({
render: function() {
var navNodes = this.props.data.map(function(nav) {
return (
<NavItem name={nav.name} key={nav.id}></NavItem>
);
});
return (
<ul className="nav">
<li className="current"><i className="glyphicon glyphicon-home"></i> Lists</li>
{navNodes}
<li><i className="glyphicon glyphicon-plus"></i> Add New Widget List</li>
</ul>
);
}
});
var NavBox= React.createClass({
loadNavsFromServer: function() {
$.ajax({
url: "http://server/api/widgetlists/?format=json",
dataType: 'json',
cache: false,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error("http://server/api/widgetlists/?format=json", status, err.toString());
}.bind(this)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadNavsFromServer();
},
render: function() {
return (
<div className="col-md-2">
<div className="sidebar content-box" style={{display: "block"}}>
<NavList data={this.state.data} />
</div>
</div>
);
}
});
module.exports = {
NavBox: NavBox
}
Content.js
var Widgets = React.createClass({
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
$.ajax({
url: 'http://server/api/widgets/?list="xxxx"&format=json',
dataType: 'json',
cache: false,
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error('http://server/api/widgets/?list="xxxx"&format=json', status, err.toString());
}.bind(this)
});
},
render: function() {
return (
<div className="col-md-10">
<div className="row">
<div className="col-md-6">
<div className="content-box-large">
<div className="panel-body">
<BootstrapTable data={this.state.data} striped={true}>
<TableHeaderColumn isKey={true} hidden={true} dataField="id">Widget ID</TableHeaderColumn>
<TableHeaderColumn dataField="title">Title</TableHeaderColumn>
<TableHeaderColumn dataField="username">Username</TableHeaderColumn>
<TableHeaderColumn dataField="price">Price</TableHeaderColumn>
</BootstrapTable>
</div>
</div>
</div>
</div>
</div>
);
}
});
module.exports = {
Widgets: Widgets
}
App.js
var Navigation = require("./components/Navigation/Navigation");
var Content = require("./components/Content/Content");
ReactDOM.render(
<Navigation.NavBox/>,
document.getElementById('navigation')
);
ReactDOM.render(
<Content.Widgets/>,
document.getElementById('content')
);
Depending on what link is clicked in Nav.js I want it to update the data in Content.js. NavItem in Nav.js would pass the list name into Content.js (the "xxxx" so that the table would load with the specific data based on that Item.
As #FakeRainBrigand mentions in his comment, this is a pretty typical use case for some type of event-based pattern like Flux.
https://facebook.github.io/flux/docs/overview.html
Basically, you want to create some type of singleton data store that keeps track of the list name. Attach a click handler to the NavItem component that causes a change to the list name in the store. The store should emit a change event in response to any changes. The Widgets component should listen for changes on the store, and when the Widgets component hears a change on the store, it should make another AJAX request with the new list item.
Let me know if you have any specific questions about implementation.
First of all I'm totally new to react so I'm not sure if my code is already written the "react way".
So far I've created a couple of react classes which render a Bootstrap Modal. To set the initial states I call an Ajax function within the componentsDidMount function. This works fine until I try to insert plain HTML into the modal body.
The server request works fine and I get plain HTML code in my this.state.data.content but if I try to insert this into the modal body I receive following error:
Error: Invariant Violation: Objects are not valid as a React child (found: object with keys {__html}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons.
Does anyone know how to fix this? Am I even doing the right thing here?
Thanks!
<script type="text/babel">
var Modal = ReactBootstrap.Modal;
var Button = ReactBootstrap.Button;
var ButtonToolbar = ReactBootstrap.ButtonToolbar;
var L5fmHeaderButton = React.createClass({
render: function() {
var iconClass = "glyphicon " + this.props.buttonIcon;
return(
<button onClick={this.props.onClick} className="lfm-Modal-Button">
<span className={iconClass} aria-hidden="true"></span>
{this.props.buttonText}
</button>
);
}
});
var L5fmModalBody = React.createClass({
rawMarkup: function() {
return { __html: this.props.content };
},
render: function() {
return(
<Modal.Body>
dangerouslySetInnerHTML={this.rawMarkup()}
</Modal.Body>
);
}
});
var L5fmModal = React.createClass({
getInitialState : function() {
return {
data : []
};
},
componentDidMount: function() {
$.ajax({
url: 'L5fm/setInitialState',
dataType: 'json',
cache: false,
success: function(data) {
this.setState({data: data});
console.log(data);
console.log(this.state.data);
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
changeDirectory : function() {
if (this.state.privateDir) {
this.setState({privateDir: false});
}
else {
this.setState({privateDir: true});
}
},
render: function() {
if(this.state.data.privateDir) {
var browseIcon = "glyphicon-folder-open";
var browseText = "browse all files";
}
else {
var browseIcon = "glyphicon-briefcase";
var browseText = "browse private files";
}
return(
<Modal {...this.props} bsSize="large" aria-labelledby="contained-modal-title-lg">
<Modal.Header closeButton>
<div className="header-button-group">
<L5fmHeaderButton buttonIcon="glyphicon-cloud-upload" buttonText="upload" />
<L5fmHeaderButton buttonIcon="glyphicon-list" buttonText="list View" />
<L5fmHeaderButton onClick={this.changeDirectory} buttonIcon={browseIcon} buttonText={browseText} />
</div>
</Modal.Header>
<L5fmModalBody content={this.state.data.content}/>
</Modal>
);
}
});
var App = React.createClass({
getInitialState: function() {
return { lgShow: false };
},
render: function() {
let lgClose = () => this.setState({ lgShow: false });
return (
<ButtonToolbar>
<Button bsStyle="primary" onClick={()=>this.setState({ lgShow: true })}>
Launch large demo modal
</Button>
<L5fmModal show={this.state.lgShow} onHide={lgClose} />
</ButtonToolbar>
);
}
});
ReactDOM.render(<App />, document.getElementById("modal"));
</script>
Well, as it seems, you are missing a div-tag where you wish to render your raw html
considering changing the Modal.Body code like this
var L5fmModalBody = React.createClass({
rawMarkup: function() {
return { __html: this.props.content };
},
render: function() {
return(
<Modal.Body>
<div dangerouslySetInnerHTML={createMarkup()} />
</Modal.Body>
);
}
});
otherwise the rendering gets broken because your markup cannot really be set as a child on the Modal.Body element
In my React.js to-do app, I'm trying to enable the return key to submit an item from my TextInput component to my ToDoList component. Right now the TextInput.inputSubmit method just console.logs the input value, but I'm wondering if I can have it trigger a prop (enter={that.addToDo}) inside of ToDoList. Or is there a better way?
JSFiddle
Edit: improved JSFiddle (courtesy of knowbody)
/** #jsx React.DOM */
var todos = [{text: "walk dog"}, {text: "feed fish"}, {text: "world domination"}, {text: "integrate return key"}];
var TextInput = React.createClass({
getInitialState: function() {
return {text: ''};
},
inputSubmit: function() {
//I think I want to trigger ToDoList's addToDo method from here?
console.log(this.refs.inputEl.getDOMNode().value);
this.setState({text: ''});
},
handleChange: function(evt) {
this.setState({text: evt.target.value});
},
handleKeyDown: function(evt) {
if (evt.keyCode === 13 ) {
return this.inputSubmit();
}
},
render: function() {
return (
<input value={this.state.text} ref="inputEl" onChange={this.handleChange} onKeyDown={this.handleKeyDown}/>
)
}
});
var SubmitButton = React.createClass({
render: function(){
return (
<button onClick={this.props.click}> Add </button>
)
}
});
var ToDo = React.createClass({
render: function(){
return (
<div>
<button onClick={this.props.click}>X</button>
<span> - {this.props.text}</span>
</div>
)
}
});
var ToDoList = React.createClass({
getInitialState: function (){
return {
todos: this.props.todos.splice(0)
}
},
deleteToDo: function(todo){
this.state.todos.splice(this.state.todos.indexOf(todo), 1);
this.setState({todos: this.state.todos});
},
addToDo: function(){
this.state.todos.push({text: this.refs.textIn.refs.inputEl.getDOMNode().value});
this.setState({
todos: this.state.todos
});
this.refs.textIn.setState({text: ''});
},
render: function(){
var that = this;
return (
<div>
{this.state.todos.map(function(todo) {
return (
<ToDo text={todo.text} click={that.deleteToDo.bind(null, todo)} />
)
})}
<br/>
<TextInput ref="textIn" enter={that.addToDo} />
<SubmitButton click={that.addToDo} />
</div>
)
}
});
React.renderComponent(<ToDoList todos={todos} />, document.body);
Your code is a bit messy but a quick fix will be to add:
this.props.enter(this.refs.inputEl.getDOMNode().value);
where your console.log() is. I will edit my answer with the full explanation once I'm on my laptop
My site works flawlessly in web browsers, but IE11 shows this error in console.
What should I do with this?
React.render(
<NewsFeed tagFilter={tagFilter}/>,
document.getElementById('newsFeed')
);
'NewsFeed' is undefined
EDIT:
Here is the newsfeed (.js JSX file, included in page's header)
var Article = React.createClass({
askDelete: function(id,title) {
if (confirm("Delete the '"+title+"'?")) {
$.ajax({
url: "/-----removed----/"+id,
type: "DELETE",
async: false,
cache: false,
dataType: 'json'
});
location.reload();
}
},
handleClick: function(id) {
React.unmountComponentAtNode(document.getElementById('editor'));
React.render(
<PostEditor
postId={id}
/>,
document.getElementById('editor')
);
functAdmin.showEditor();
},
render: function() {
var editIcon=[];
var boundClick = this.handleClick.bind(this, this.props.id);
var boundDeleteClick = this.askDelete.bind(this, this.props.id,this.props.title);
editIcon.push(<span className="adminActionsNewsfeed" key={"editIcon"+this.props.id}><i className="pointer gray fa fa-edit" onClick={boundClick}></i><i className="pointer fa fa-remove red" onClick={boundDeleteClick} key={"deleteNewsIcon"+this.props.id}></i></span>);
var tags=[];
if (typeof this.props.tags != 'undefined') {
var tagArray=this.props.tags.split(",");
for(tag of tagArray){
tags.push({tag});
}
}
return (
<div className="article" key={"newsArticle"+this.props.id}>
{editIcon}
<span className="articleTitle">
{this.props.title}
</span>
<span className="articleTime">
{funct.formatDate(this.props.time)}
</span>
<div className="articleBody">
{this.props.children}
</div>
<div className="tagLine">{tags}</div>
</div>
);
}
});
var ArticleList = React.createClass({
render: function() {
this.props.data.sort(funct.SortByTime);
var postNodes = this.props.data.map(function (item) {
var tags = item.news_tags.toLowerCase().split(",");
if ((tagFilter=="") || (tags.indexOf(tagFilter) > -1)) {
return (
<Article
key={"news"+item.news_id}
title={item.news_title}
tags={item.news_tags}
time={item.news_time}
id={item.news_id}
>
{item.news_body}
</Article>
);
}
});
return (
<span>
{postNodes}
</span>
);
}
});
var NewsFeed = React.createClass({
launchAdd: function() {
React.unmountComponentAtNode(document.getElementById('editor'));
React.render(
<PostEditor
postId={""}
/>,
document.getElementById('editor')
);
functAdmin.showEditor();
},
getInitialState: function() {
return {data: []};
},
refreshPostStatus: function() {
$.ajax({
url: "/-----removed----",
type: "GET",
cache: false,
dataType: 'json',
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.log( xhr.responseText);
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
componentDidMount: function() {
this.refreshPostStatus();
},
render: function() {
var addIcon=[];
addIcon.push(<div className="addPostLine"><i className={funct.statusIcon[5]+" fa-2x"} onClick={this.launchAdd} />Add new post</div>);
return (
<span>
<i className="fa fa-file fa-lg blue"></i>
{addIcon}
<h1>Netbiter funct System Information</h1>
<ArticleList data={this.state.data}/>
</span>
);
}
});
Solved it.
IE11 didn't like this part of newsfeed.js:
for(tag of tagArray){
tags.push({tag});
}
It works after replacing it with this:
for(var i in tagArray){
var tag=tagArray[i];
tags.push({tag});
}
just import 'core-js/es6/' to your index.js or main entry file
import 'core-js/es6/';
import React from 'react';
import ReactDOM from 'react-dom';
import App from './app';
ReactDOM.render(<App />, document.getElementById('root'));