I have this function that sets the date from two weeks ago:
dateTwoWeeksAgo: function(){
var twoWeeksAgo = new Date().toDateString();
this.setState({twoWeeksAgo: twoWeeksAgo});
},
I have this code that calls this function. But it is not working. how do I display a variable I am setting the state of or returning from a function?
<h2 className="headings" id="commitTotal"> Commits since {this.dateTwoWeeksAgo} : {this.state.commits.length} </h2>
Option 1: In order to display the value of twoWeeksAgo held on you state you can:
<h2 className="headings" id="commitTotal"> Commits since {this.state.twoWeeksAgo} : {this.state.commits.length} </h2>
The actual method which updates your state - dateTwoWeeksAgo() - could be called for example in the componendDidMount lifefycle method.
https://facebook.github.io/react/docs/component-specs.html#mounting-componentdidmount
Here is a demo: http://codepen.io/PiotrBerebecki/pen/LRAmBr
Option 2: Alternatively, you can just call a method which returns the required date like so (http://codepen.io/PiotrBerebecki/pen/NRzzaX),
const App = React.createClass({
getInitialState: function() {
return {
commits: ['One', 'Two']
};
},
dateTwoWeeksAgo: function() {
return new Date().toDateString();
},
render: function() {
return (
<div>
<h2 className="headings" id="commitTotal"> Commits since {this.dateTwoWeeksAgo()} : {this.state.commits.length} </h2>
</div>
);
}
})
Code option 1:
const App = React.createClass({
getInitialState: function() {
return {
twoWeeksAgo: null,
commits: ['One', 'Two']
};
},
componentDidMount: function() {
this.dateTwoWeeksAgo();
},
dateTwoWeeksAgo: function() {
var twoWeeksAgo = new Date().toDateString();
this.setState({twoWeeksAgo: twoWeeksAgo});
},
render: function() {
return (
<div>
<h2 className="headings" id="commitTotal"> Commits since {this.state.twoWeeksAgo} : {this.state.commits.length} </h2>
</div>
);
}
})
ReactDOM.render(
<App />,
document.getElementById('app')
);
It should be:
<h2 className="headings" id="commitTotal"> Commits since {this.state.dateTwoWeeksAgo} : {this.state.commits.length} </h2>
The difference is this.state.dateTwoWeeksAgo
For your example of code I suggest this approach
dateTwoWeeksAgo: function(){
return new Date().toDateString();
},
<h2 className="headings" id="commitTotal"> Commits since {this.dateTwoWeeksAgo()} : {this.state.commits.length} </h2>
if you really want to use state you need to change {this.dateTwoWeeksAgo} to {this.state.dateTwoWeeksAgo}
Related
I'm trying make an AJAX call to get server data into my React Components.
I'm unable to display it with React. I get this error:
Uncaught TypeError: Cannot read property 'map' of undefined
I've done research http://andrewhfarmer.com/react-ajax-best-practices/ and reactjs - Uncaught TypeError: Cannot read property 'map' of undefined ;however, I'm not sure how to map it to my react component.
Here is my code below:
var items;
$.get("http://localhost:3000/getProducts", function( data ) {
items = data;
this.state.items = data;
});
/*React Code Below */
var RepeatModule = React.createClass({
getInitialState: function() {
return { items: [] }
},
render: function() {
var listItems = this.props.items.map(function(item) {
return (
<div className='brick'>
<div>
<a target='_blank' href={item.productURL}><img src={item.imageURL}/></a>
<p className='itemName'>Short Sleeve Oxford Dress Shirt, White, Large</p>
<p className='storeName'>Nike Factory Store</p>
<img className='foundPicture' src='../images/rohit.png'/>
</div>
</div>
);
});
return (
<div>
{listItems}
</div>
);
}
});
ReactDOM.render(<RepeatModule items={items} />,
document.getElementById('clothing-content'));
My JSON array with item properties are valid:
Here is the array below:
[ { _id: 584d1e36a609b545b37611ac,
imageURL: 'http://ih1.redbubble.net/image.252113981.3904/ra,unisex_tshirt,x1350,fafafa:ca443f4786,front-c,30,60,940,730-bg,f8f8f8.u2.jpg',
productName: 'Drake',
productType: 'T-Shirts & Hoodies',
price: '$29.97',
productURL: 'http://www.redbubble.com/people/misfitapparel/works/22923904-drake?grid_pos=6&p=t-shirt',
__v: 0 } ]
Why is this error occurring? And how should it be implemented?
Javascript is asynchronous. Your get function callback does not block program flow, it executes at a later time. The rest of your code will continue to execute. You're sending an AJAX request asynchronously, then you're rendering a react component with an undefined variable. Then, at a later time, the get request will finish and your data will be populated, but this is long after rendering has completed.
The simplest solution here is to only render the component once your AJAX request has finished:
var RepeatModule = React.createClass({
render: function() {
var listItems = this.props.items.map(function(item) {
return (
<div className='brick'>
<div>
<a target='_blank' href={item.productURL}><img src={item.imageURL}/></a>
<p className='itemName'>Short Sleeve Oxford Dress Shirt, White, Large</p>
<p className='storeName'>Nike Factory Store</p>
<img className='foundPicture' src='../images/rohit.png'/>
</div>
</div>
);
});
return (
<div>
{listItems}
</div>
);
}
});
$.get("http://localhost:3000/getProducts", function( data ) {
ReactDOM.render(<RepeatModule items={data} />,
document.getElementById('clothing-content'));
});
A better solution, depending on your needs, is probably to do the AJAX request in a componentDidMount lifecycle method, and store the result in state instead of props.
var RepeatModule = React.createClass({
getInitialState: function() {
return { items: this.props.items || [] }
},
componentWillMount: function() {
console.log("componentWillMount()")
$.get("http://localhost:3000/getProducts", function( data ) {
this.setState({ items : data })
console.log(data,"data is here");
}.bind(this));
},
render: function() {
var listItems = this.state.items.map(function(item) {
return (
<ListItem item={item}/>
);
});
return (
<div>
{listItems}
</div>
);
}
});
/* make the items stateless */
var ListItem = function(props) {
return (
<div className='brick' key={props.item._id}>
<div>
<a target='_blank' href={props.item.productURL}><img src={props.item.imageURL}/></a>
<p className='itemName'>Short Sleeve Oxford Dress Shirt, White, Large</p>
<p className='storeName'>Nike Factory Store</p>
<img className='foundPicture' src='../images/rohit.png'/>
</div>
</div>
);
}
var data = []
ReactDOM.render(<RepeatModule items={data} />, document.getElementById('clothing-content'));
I had to bind the data and use componentWillMount.
I saw some questions speaking about similar issues but somehow I still do not manage to solve my issue so here I am asking for your kind help. I am pretty new to React and would like to send a function from a Parent to a child and then use it from the Child but somehow when I want to use it it says
Uncaught TypeError: Cannot read property 'props' of undefined"
Edited Code after first answers were helping:
var Menu = React.createClass({
links : [
{key : 1, name : "help", click : this.props.changePageHelp}
],
render : function() {
var menuItem = this.links.map(function(link){
return (
<li key={link.key} className="menu-help menu-link" onClick={link.click}>{link.name}</li>
)
});
return (
<ul>
{menuItem}
</ul>
)
}
});
var Admin = React.createClass ({
_changePageHelp : function() {
console.log('help');
},
render : function () {
return (
<div>
<div id="menu-admin"><Menu changePageHelp={this._changePageHelp.bind(this)} /></div>
</div>
)
}
});
ReactDOM.render(<Admin />, document.getElementById('admin'));
Pass a value from Menu function and recieve it in the changePageHelp function and it works.
var Menu = React.createClass({
render : function() {
return (
<div>
{this.props.changePageHelp('Hello')}
</div>
)
}
});
var Admin = React.createClass ({
_changePageHelp : function(help) {
return help;
},
render : function () {
return (
<div>
<div id="menu-admin"><Menu changePageHelp={this._changePageHelp.bind(this)} /></div>
</div>
)
}
});
ReactDOM.render(<Admin />, document.getElementById('admin'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="admin"></div>
For performance reasons, you should avoid using bind or arrow functions in JSX props. This is because a copy of the event handling function is created for every instance generated by the map() function. This is explained here: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md
To avoid this you can pull the repeated section into its own component. Here is a demo: http://codepen.io/PiotrBerebecki/pen/EgvjmZ The console.log() call in your parent component receives now the name of the link. You could use it for example in React Router.
var Admin = React.createClass ({
_changePageHelp : function(name) {
console.log(name);
},
render : function () {
return (
<div>
<div id="menu-admin">
<Menu changePageHelp={this._changePageHelp} />
</div>
</div>
);
}
});
var Menu = React.createClass({
getDefaultProps: function() {
return {
links: [
{key: 1, name: 'help'},
{key: 2, name: 'about'},
{key: 3, name: 'contact'}
]
};
},
render: function() {
var menuItem = this.props.links.map((link) => {
return (
<MenuItem key={link.key}
name={link.name}
changePageHelp={this.props.changePageHelp}
className="menu-help menu-link" />
);
});
return (
<ul>
{menuItem}
</ul>
);
}
});
var MenuItem = React.createClass ({
handleClick: function() {
this.props.changePageHelp(this.props.name);
},
render : function () {
return (
<li onClick={this.handleClick}>
Click me to console log in Admin component <b>{this.props.name}</b>
</li>
);
}
});
ReactDOM.render(<Admin />, document.getElementById('admin'));
http://jsfiddle.net/adamchenwei/3rt0930z/20/
I just trying to create an example to learn how state works in a list.
What I intent to do is to allow a particular value that got repeated in a list, to change, in ALL items in the list, by using state. For example, in this case, I want to change all the list item's name to 'lalala' when I run changeName of onClick.
However I have this warning (issue at fiddle version 11, resolved at version 15)
Any help on resolving it to achieve purpose above?
Actual Code
var items = [
{ name: 'Believe In Allah', link: 'https://www.quran.com' },
{ name: 'Prayer', link: 'https://www.quran.com' },
{ name: 'Zakat', link: 'https://www.quran.com' },
{ name: 'Fasting', link: 'https://www.quran.com' },
{ name: 'Hajj', link: 'https://www.quran.com' },
];
var ItemModule = React.createClass({
getInitialState: function() {
return { newName: this.props.name }
},
changeName() {
console.log('changed name');
this.setState({ newName: 'lalala' });
},
render() {
//<!-- <a className='button' href={this.props.link}>{this.props.name}</a> -->
return (
<li onClick={this.changeName}>
{this.state.newName}
</li>
);
}
});
var RepeatModule = React.createClass({
getInitialState: function() {
return { items: [] }
},
render: function() {
var listItems = this.props.items.map(function(item) {
return (
<div>
<ItemModule
key={item.name}
name={item.name} />
</div>
);
});
return (
<div className='pure-menu'>
<h3>Islam Pillars</h3>
<ul>
{listItems}
</ul>
</div>
);
}
});
ReactDOM.render(<RepeatModule items={items} />,
document.getElementById('react-content'));
-UPDATE-
fiddle version 16
updated fidle, now there is issue with key, also, the onClick did not update the value for all the list item. Is there something wrong I did?
-UPDATE-
fiddle version 20
Now the only issue is change all the list item's name to 'lalala' when I run changeName of onClick.
remove the parenthesis from
onClick={this.changeName()},
so
onClick={this.changeName}
you want to call the function onClick, but you are calling it on render that way
I think you meant to do onClick={this.changeName}
In the way you have it you are calling the changeName function on render instead of on click.
I have a dynamic list of children, that are form inputs.
ex:
var FormRows = React.createClass({
getInitialState: function() {
return {
rows: []
}
},
createRows: function() {
this.props.values.maps(value){
rows.push(<FormRow ...handlers... ...props... value={value} />
}
},
addNewRow{
// add a new row
},
render: function() {
return (
<div>
{this.state.rows}
</div>
);
});
var FormRow = React.createClass({
getInitialState: function() {
return {
value: this.props.value || null
}
},
render: function() {
<input type='text' defaultValue={this.state.value} ...changeHandler ... }
}
});
This is a dumbed down version , but the idea, is a its a dynamic form, where the user can click a plus button to add a row, and a minus button, which will set the row to visibility to hidden.
This state is nested n levels deep. What is the best way to actually get the state out of the children, and submit the form? I can use 'ref' add a function to getFormValue(): { return this.state.value } to the FormRow button, but i'm not sure if thats the best practice way.
I find myself using this pattern quite often, an array of undetermined size of children, that need to pass the state up.
Thanks
It’s not a dumb question at all, and a good example of using flux principals in React. Consider something like this:
var App
// The "model"
var Model = {
values: ['foo', 'bar'],
trigger: function() {
App.forceUpdate()
console.log(this.values)
},
update: function(value, index) {
this.values[index] = value
this.trigger()
},
add: function() {
this.values.push('New Row')
this.trigger()
}
}
var FormRows = React.createClass({
addRow: function() {
Model.add()
},
submit: function() {
alert(Model.values);
},
render: function() {
var rows = Model.values.map(function(value, index) {
return <FormRow key={index} onChange={this.onChange} index={index} value={value} />
}, this)
return (
<div>{rows}<button onClick={this.addRow}>Add row</button><button onClick={this.submit}>Submit form</button></div>
)
}
})
var FormRow = React.createClass({
onChange: function(e) {
Model.update(e.target.value, this.props.index)
},
render: function() {
return <input type='text' defaultValue={this.props.value} onChange={this.onChange} />
}
});
App = React.render(<FormRows />, document.body)
I used a simplified model/event example using Array and forceUpdate but the point here is to let the model "own" the form data. The child components can then make API calls on that model and trigger a re-render of the entire App with the new data (Flux).
Then just use the model data on submit.
Demo: http://jsfiddle.net/ekr41bzr/
Bind values of inputs to some model (for example build in Backbone or Flux) and on submit retrieve values from there, without touching inputs.
I'm trying to create a todo list where after you finish one task,
only then will the next task be enabled (to tick as finished).
Here is what I have so far:
/** #jsx React.DOM */
$(function(){
var tasks = [
{title: "Wake up"},
{title: "Eat dinner"},
{title: "Go to sleep"}
];
var Task = React.createClass({
getInitialState: function(){
return {locked:true, done:false}
},
handleClick: function(e){
this.setState({done: !this.state.done});
var selector = '.toggle[data-order="'+(this.props.order+1)+'"]';
this.setState({locked: true})
console.log(selector)
console.log($(selector).removeAttr("disabled"))
},
render: function() {
var locked;
//Fix first task to not be disabled
if(this.props.order == 0 && this.state.done === false)
locked = false;
else
locked = this.state.locked;
var done = this.state.done ? "Done":"Not done";
var classView = "task" + (this.state.done ? " done":" not-done");
return (
<div class="todo well well-sm" class={classView}>
<span class="description">{this.props.title}</span>
<button type="button" onClick={this.handleClick} data-order={this.props.order} disabled={locked} class="toggle btn btn-default btn-xs pull-right">
<span class="glyphicon glyphicon-unchecked"></span> Done
</button>
</div>
);
}
});
var TaskList = React.createClass({
render: function(){
var i = -1;
var taskNodes = this.props.data.map(function (task) {
return <Task title={task.title} order={++i} />;
});
return (
<div class="task-list">
{taskNodes}
</div>
);
}
});
var Guider = React.createClass({
render: function(){
return (
<div>
<TaskList data={this.props.data} />
</div>
);
}
});
React.renderComponent(<Guider data={tasks} />, document.body);
});
The next buttons are still not disabled, and I feel that I'm doing something wrong in general (not in accordance with the react "zen").
Btw:
How can I change the state for a dom element without the user triggering it? is there any id I should use?
If you initiate the data into non-root component, it becomes hard to update other components. So I prefer keeping data into root component, Then pass a click handler as props. Now you'll have access to that handler inside non-root component. Calling that will update root component and so the other non-root components.
Here's working jsFiddle - http://jsfiddle.net/ammit/wBYHY/5/
Example -
var Task = React.createClass({
handleClick: function (e) {
// Passing order of task
this.props.clicked(order);
},
render: function () {
return ( <button type="button" onClick={this.handleClick}></button> );
}
});
var TaskList = React.createClass({
getInitialState: function(){
// initiate tasks here
},
whenClicked: function(order){
// Revise the tasks using `order`
// Finally do a setState( revised_tasks );
},
render: function(){
return ( <Task clicked={this.whenClicked} /> );
}
});