I've got a simple react component/sub-component structure. On the subcomponent, I'm trying to loop through an array of objects and output a property value on that object.
There is always a single empty text node displayed at the top of the list I'm outputting and I can't figure out why it's there or how to make it go away.
A view from React's Dev Tools
Here's my Code:
'use strict'
var React = require('react'),
ReactDOM = require('react-dom')
var UpcomingMovieList = React.createClass({
render: function() {
return(<UpcomingMovie movies={this.props}/>)
}
})
var UpcomingMovie = React.createClass({
render: function() {
console.log(this)
var movie = this.props.movies.movies.map(function(element, index) {
// console.log(element)
return(<div className='movie' key={element.id}><div className='movie-content'>{element.title}</div></div>)
})
return(<div>UpcomingMovie.{movie}</div>)
}
})
ReactDOM.render(<UpcomingMovieList movies={window.data.movies}/>,
document.getElementById('app-container')
)
window.data.movies is just an array of objects. I'm just trying to output the title for the moment.
Try this instead:
var UpcomingMovie = React.createClass({
render: function() {
return (
<div>
<h2>Upcoming Movies</h2>
{this.props.movies.movies.map(function(element, index) {
// console.log(element)
return(<div className='movie' key={element.id}><div className='movie-content'>{element.title}</div></div>)
})}
</div>
);
}
});
It would be more ideal to do the iteration from the UpcomingMovieList component though:
var UpcomingMovieList = React.createClass({
render: function() {
return this.props.movies.map((movie) => {
return <UpcomingMovie movie={movie} />
});
}
});
var UpcomingMovie = React.createClass({
render: function() {
var movie = this.props.movie;
return (
<div className='movie' key={movie.id}>
<div className='movie-content'>{movie.title}</div>
</div>
);
}
});
Related
In the ArticlesGrid example we have the following render function:
render () {
return this.state.articles && (
<div className='articles'>
{ this.state.articles.map( function (article) {
return <Article article={article} key={article.id} />;
})}
</div>
);
}
So we have a component Article which has as one of it's props article which equals the object article, so far so good
Could someone explain what's going on with the next statement:
var Article = function({article}) {
why isn't it
var Article = function(this.props.article) {
??
in fact, when I try to console.log this.props I get undefined. I thought Article was a component too.
UPDATE: Here's the entire code:
class ArticlesGrid extends React.Component {
constructor(props) {
super(props);
this.state = {
articles: []
};
}
componentDidMount () {
var url =
'http://api.nytimes.com/svc/search/v2/articlesearch.json?'
+ 'api-key=d68154fxxxxxxxxxxxxxxxxc7f5';
$.getJSON(url, function(data, status) {
return this.setState({articles: this.parse(data)});
}.bind(this));
}
parse(results) {
if(!results || !results.response) return [];
var articles = results.response.docs;
var parsedArticles = [];
for (var i = 0; i < articles.length;i++){
var article = articles[i];
if (article.multimedia.find(this.isXL)) {
parsedArticles.push({
id: article._id,
title: article.headline.main || 'Untitled',
imageURL: article.multimedia.find(this.isXL).url || '#',
webURL: article.web_url || '#'
});
}
}
return parsedArticles;
}
isXL (image) {
return image.subtype === 'xlarge';
}
render () {
return this.state.articles && (
<div className='articles'>
{ this.state.articles.map( function (article) {
return <Article article={article} key={article.id} />;
})}
</div>
);
}
}
var Article = function({article}) {
var imgURL = 'https://static01.nyt.com/' + article.imageURL;
return (
<div className='article'>
<a className='article-link' href={article.webURL}>
<img className='article-image'
title={article.title}
src={imgURL} />
</a>
</div>
);
}
ReactDOM.render(<ArticlesGrid/>,document.getElementById('container'));
when I try to console.log this.props I get undefined. I thought
Article was a component too.
Yes Article is a component too but it is a functional component. props to this are passed as argument to this function. So if you want to log props of this component then you can do it following way
var Article = function(props) {
console.log(props)
var imgURL = 'https://static01.nyt.com/' + article.imageURL;
What is var Article = function({article}) {
This is called object destructuring. It means that if an object is passed to this function then take article property of that object. So basically
var Article = function({article}) {
roughly means
var Article = function(props) {
var article = props.article
...
I have the following react component for a dropdown:
var UIDropdown = React.createClass({
getDefaultProps: function () {
return {
isOpen: false
};
},
render: function () {
if (this.props.isOpen) {
return (
<div className="dropdown">
<ul className="uk-nav uk-nav-dropdown tm-svg-center">
{this.props.mapOpacityValues.map(function (list, i) {
return (
<li onClick={this.props.opacityThermatic.bind(this, list) } key={"list" + i}>{`${list * 100}%`}</li>
);
}, this) }
</ul>
</div>
);
}
return null;
}
});
I'm looping through some data which outputs some list items, but I have a number for different data items.
How can I add the following in the component without repeating the dropdown component code:
{this.props.mapOpacityValues.map(function (list, i) {
return (
<li onClick={this.props.opacityThermatic.bind(this, list) } key={"list" + i}>{`${list * 100}%`}</li>
);
}, this) }
Example but with a single dropdown component
https://jsfiddle.net/zidski/ddLdg84s/
If I understand you correctly, you need to reuse your Dropdown component
Then do something like this
DropdownItems component
var DropdownItems = React.createClass({
render: function () {
return(
<ul className="uk-nav uk-nav-dropdown tm-svg-center">
{this.props.mapOpacityValues.map(function (list, i) {
return (
<li onClick={this.props.opacityThermatic.bind(this, list) } key={"list" + i}>{`${list * 100}%`}</li>
);
}, this)
}
</ul>
)
}
});
UIDropdown component
var UIDropdown = React.createClass({
getDefaultProps: function () {
return {
isOpen: false
};
},
render: function () {
if (this.props.isOpen) {
return (
<div className="dropdown">
{this.props.children}
</div>
);
}
return null;
}
});
Then you can create any number UIDropdowns like
<UIDropdown>
<DropdownItems mapOpacityValues={someData} opacityThermatic={someFunction}>
</UIDropdown>
Here you need to repeat neither dropdown nor li items. You just resue them in your implementation.
First time chart components is rendered correctly. When I am changing the tab on dashboard and again click on show charts I am getting error this.dataTable.getNumberOfRows is not a function. When I am mounting chart component again then I am getting error.
chart component:
var React = require('React');
var ReactDOM = require('ReactDOM');
var {Chart} = require('react-google-charts');
var $ = require('jquery');
var LineChart = React.createClass({
getInitialState: function() {
return {
rows: [],
}
},
componentWillMount: function () {
this.sTime = this.props.sTime;
this.eTime = this.props.eTime;
var _this = this;
var request = function () {
$.post("/times" , {'start':_this.sTime, 'end':_this.eTime }, function (res) {
_this.setState({
rows: res.data
});
});
};
request();
},
render: function() {
return (
<div >
<Chart chartType="LineChart"
rows={this.state.rows}
columns={this.props.columns}
options={this.props.options}
/>
</div>
);
}
});
module.exports = LineChart;
I need to define initial value of rows. This solve the problem.
getInitialState: function() {
return {
rows: [[new Date(0),0]],
}
},
I'm using react-router which forces me to use React.cloneElement to pass down properties to my Children. I can pass down objects and functions, but my issue is where one of my functions has a return object back up to the parent, which is always undefined. The function triggers in the parent, but it doesn't receive the object I'm passing it from the child.
Here is a jsFiddle of the below example code if anyone wants to edit it https://jsfiddle.net/conor909/gqdfwg6p/
import React from "react";
import ReactDom from "react-dom";
const App = React.createClass({
render() {
return (
<div>
{this.getChildrenWithProps()}
</div>
)
},
getChildrenWithProps() {
return React.Children.map(this.props.children, (child) => {
return React.cloneElement(child, {
myFunction: this.myFunction
});
});
},
// NOTE:
// the idea is that the variable 'newForm' should be sent back up to App, I can log out 'newForm' in the Child, but here in App, it is undefined.
myFunction(newForm) {
console.log(newForm); // => undefined object
}
});
const Child = React.createClass({
propTypes: {
myFunction: React.PropTypes.func,
myForm: React.PropTypes.object
},
render() {
return (
<form className="col-sm-12">
<MyForm
changeForm={this.onChangeForm}
form={this.props.myForm} />
</form>
)
},
onChangeForm(formChanges) {
let newForm = {
...this.props.myForm,
...formChanges
}
// console.log(newForm); => here my newForm object looks fine
this.props.myFunction(newForm);
}
});
const MyForm = React.createClass({
propTypes: {
changeForm: React.PropTypes.func.isRequired
},
render() {
return (
<div>
<Input onChange={this.onChangeForm}>
</div>
)
},
onChangeForm(value) {
this.props.changeForm({ something: value });
}
});
So, I believe this is a formatting issue OR I'm not clear about how the return works when dynamically building.
The render function in Results works, if I replace the code with anythign else it renders where I want. Similarly, the console.log's in the Results function outputs the data correctly. There's no error, it just doesn't render the html and it doesn't hit the debugger in SynonymElement.
What am I missing in here / what core concept am I misconstruing?
(This is just an input form that takes a word, user hits submit, it returns an object with the word as a key and the value an array of synonynms. that get rendered in the ul)
'use strict'
const Smithy = React.createClass({
dsiplayName: "Smithy",
getInitialState: function() {
return { data: []};
},
handleSubmit: function(data) {
$.get('/get-synonyms', { data: data.data }).done(function(data) {
this.setState({ data: data})
}.bind(this));
},
render: function() {
return (
<div className="smithy">
<h1>Craft Tweet</h1>
<SmithyForm onSubmit={this.handleSubmit} />
<Results data={this.state.data} />
</div>
)
}
})
const SmithyForm = React.createClass({
displayName: "SmithyForm",
getInitialState: function() {
return { placeholder: "tweet", value: "" };
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
handleSubmit: function(event) {
event.preventDefault();
var tweet = this.state.value.trim();
this.props.onSubmit({ data: tweet });
this.setState({value: ''});
},
render: function() {
var placeholder = this.state.placeholder;
var value = this.state.value;
return (
<form className="smithyForm" onSubmit={this.handleSubmit}>
<input type="text" placeholder={placeholder} value={value} onChange={this.handleChange} />
<button>smithy</button>
</form>
);
}
})
const SynonymElement = React.createClass({
render: function() {
debugger
return (
<li>{this.props.data}</li>
)
}
})
const Results = React.createClass({
render: function() {
var words = this.props.data;
return (
<div className="results">
{
Object.keys(words).map(function(value) {
{ console.log(value) }
<div className={value}>
<ul>
{
words[value].map(function(syn) {
{ console.log(syn) }
return <SynonymElement data={syn} />
})
}
</ul>
</div>
})
}
</div>
)
}
})
ReactDOM.render(<Smithy />, document.getElementsByClassName('container')[0])
Might have some other complicating issues but assuming everything else is wired up correctly, you need to return the result of the function you pass into the first map (over the collection Object.keys(words)) just as you have for the later map otherwise the function is executed and nothing useful is returned.
Possibly just a dupe of loop inside React JSX
return (
<div className="results">
{
Object.keys(words).map(function(value) {
return ( // <-- this
<div className={value}>