I am new to react.js and I have stumbled upon a subject I can't wrap my head around. I have a long array of items which I want to display in two different rows, which is why I take chunks out of this array and add them to a nested array without key and values like so:
constructor(props) {
super(props)
this.state = {
characters: [["Anakin","Darth Vader","Snoke"], ["Darth Maul", "Yoda", "Luke Skywalker"]],
}
}
In the render function of the "Characters" component I use the map function and what I want is each array to be passed to the component "Subarray":
Characters component
render() {
return (
<div>
{this.state.characters.map((item, index )=> <Subarray key={index} title={item}></Subarray>)}
</div>
)
}
And then in the "Subarray" component I want to add a html element to every element in that array:
Subarray component
export class Subarray extends Component {
render() {
return (
<div>
{this.props.title}
</div>
)
}
}
I can't get each element of the array to be wrapped within a div element:
Output:
<div><div>AnakinDarth VaderSnoke</div><div>Darth MaulYodaLuke Skywalker</div></div>
You can do this, assuming this.props.title contains ["Anakin","Darth Vader","Snoke"] :
export class Subarray extends Component {
render() {
return (
<div>
{this.props.title.map((each, index) => <div key={index}>{each}</div>)}
</div>
)
}
}
I think that you have to change Subarray to be something like
export class Subarray extends Component {
render() {
return (
<div>
{this.props.title.map((item, index) => {
return <div key={index}>{item}</div>
})}
</div>
)
}
}
in this way you loop through each item in the subarray and render every one of them
Related
I am trying to show the number 0 on the screen using props. However nothing shows on the screen and I am not sure why. This is the code:
import React,{Component} from 'react';
import Toolbar from './Toolbar.js';
class Counter extends Component {
constructor(props) {
super(props);
this.state ={
counter:0
}
};
render() {
return(
<div>
{this.state.counter.map(count=>(
<Toolbar count={count}/>
))}
</div>
)
}
};
export default Counter;
And this is where I called it
<div className="toolbar__cart">
<span>{props.count}</span>
<img src="Images/basket.png" alt="Basket" width="40"/></div>
I don't think the map function is applicable here since the value of counter is an integer and not an array. See here for more info on the map function.
If you just want your Toolbar component to display the value of this.state.counter, you could use this:
return(
<Toolbar count={this.state.counter}></Toolbar>
)
And then your Toolbar component would use that counter value like this:
function Toolbar(props) {
return (
<div>
<span>{props.count}</span>
<img src="Images/basket.png" alt="Basket" width="40"/>
</div>
)
}
You are using map function incorrectly.
.map is a function used along with an array
Check out : https://www.w3schools.com/jsref/jsref_map.asp
Correct Code :
render() {
return (
<div>
<Toolbar count={this.state.counter} />
</div>
);
}
You can checkout full code here : https://codesandbox.io/s/naughty-lederberg-hb4wp?file=/src/App.js:203-309
counter.map map function for Arrays - sample
import React,{Component} from 'react';
import Toolbar from './Toolbar.js';
class Counter extends Component {
constructor(props) {
super(props);
this.state ={
counter:[0,1,2]
}
};
render() {
return(
<div>
{this.state.counter.map(count=>(
<Toolbar count={count}/>
))}
</div>
)
}
};
I retrieve an array of data through fetch from an API. In my React Component, when I use mapStateToProps and .map(), I am able to display the contents of the array. However, if I try to get just one element from the array like array[0], it keeps returning undefined.
/* HomePage class Component: Ascendent of Banner */
class HomePage extends Component {
componentWillMount() {
this.props.fetchMovies();
}
render() {
const movie = this.props.movies[0];
return (
<div>
<Banner movies={this.props.movies} movie={movie} />
<Movies movies={this.props.movies} />
</div>
);
}
}
HomePage.propTypes = {
fetchMovies: PropTypes.func.isRequired,
movies: PropTypes.array.isRequired
};
const mapStateToProps = state => ({
movies: state.movies.movies
});
export default connect(
mapStateToProps,
{ fetchMovies }
)(HomePage);
/* Banner class Component: Descendent of HomePage */
class Banner extends Component {
render() {
const movieList = this.props.movies.map(movie => {
return <li>{movie.title}</li>;
});
return (
<div style={styles.BannerContainer}>
<div style={styles.Banner}>
<div style={styles.BannerText}>
<h1 style={styles.BannerTextHeader}>{this.props.movie.title}</h1>
<p style={styles.BannerTextParagraph}>
Arthur Curry learns that he is the heir to the underwater kingdom
of Atlantis, and must step forward to lead his people and be a
hero to the world.
</p>
<ul>{movieList}</ul>
<Button content={"Check It Out"} />
</div>
<div style={styles.BannerImage} />
<div style={styles.BannerOverlay} />
</div>
</div>
);
}
}
export default Banner;
I expect this.props.movie.title to equal this.props.movies[0].title, but the actual output is an error saying cannot get title of undefined.
The reason is that this.props.movies is undefined on first render )until you make the call to fetchMovies).
Consider checking if it exists first like this:
class HomePage extends Component {
componentWillMount() {
this.props.fetchMovies();
}
render() {
if (this.props.movies && this.props.movies[0]) {
const movie = this.props.movies[0];
return (
<div>
<Banner movies={this.props.movies} movie={movie} />
<Movies movies={this.props.movies} />
</div>
);
} else {
<div>Loading...</div>;
}
}
}
Why don't you access
{this.props.movie.title}
Like
{this.props.movie[0].title}
Seems more logical to me. And this might be the solution.
correct me if i am wrong.
And could you also console.log {this.props.movie}
Initially movies may be empty array and since you are accessing zero index position you should check it’s length before accessing zero index.
Change
const movie = this.props.movies[0];
To
if(this.props.movies.length){
const movie = this.props.movies[0];
console.log(movie);
}
Since movies is always an array so checking directly it’s length will resolve the issue
I have a React.JS component that will map the notes variable to display.
However, I have run into the problem of having no notes and receiving an error. What is a proper way to approach this?
Here is the code:
import React, {Component} from 'react';
class List extends Component {
constructor(props){
super(props);
}
render(){
var notes = this.props.items.map((item, i)=>{
return(
<li className="listLink" key={i}>
<p>{item.title}</p>
<span>{item.content}</span>
</li>
)
});
return(
<div className='list'>
{notes}
</div>
);
}
}
export default List;
If you want to render the notes when at least one note exists and a default view when there are no notes in the array, you can change your render function's return expression to this:
return(
<div className='list'>
{notes.length ? notes : <p>Default Markup</p>}
</div>
);
Since empty arrays in JavaScript are truthy, you need to check the array's length and not just the boolean value of an array.
Note that if your items prop is ever null, that would cause an exception because you'd be calling map on a null value. In this case, I'd recommend using Facebook's prop-types library to set items to an empty array by default. That way, if items doesn't get set, the component won't break.
here is the simplest way to deal with
import React, {Component} from 'react';
class List extends Component {
constructor(props){
super(props);
}
render(){
var notes = this.props.items?.map((item, i)=>{
return(
<li className="listLink" key={i}>
<p>{item.title}</p>
<span>{item.content}</span>
</li>
)
});
return(
<div className='list'>
{notes}
</div>
);
}
}
export default List;
just try to add "?" for the array that you maped
You can just setting a fallback value for the this.props.item
render() {
const items = this.props.items || [] // if there's no items, give empty array
const notes = items.map((item, i) => {
return(
....
Doing .map() on empty array will not produces an error, but will return an empty array. Which is fine because empty array is a renderable item in react and won't produce error in render() and will not render the notes as there are no notes provided.
In your component, you can set the defaultProps property to set the initial value to your props:
static defaultProps = {
items: []
};
When an array of children are passed as prop and looped over to render in parent component, react is complaining about missing unique key identifier on array iteration.
What is the correct way to overcome the warning?
Can I pass key along with children under prop.
If I want to set key to children while rendering in parent, it is complaining child's key prop is read only.
Would be easier if you shared some code.
You shouldn't need to iterate the children to render then, unless you are augmenting them in some way.
class MyComponent extends React.Component {
render() {
return (
<div>
{this.props.children}
</div>
)
}
}
If you must, can you wrap them in a div and apply the key to that instead?
class MyComponent extends React.Component {
render() {
return (
<div>
{this.props.children.map((child, index) => (<div key={index}>{child}</div>))}
</div>
)
}
}
I haven't tried this but you might be able to clone the element and change the key
class MyComponent extends React.Component {
render() {
return (
<div>
{this.props.children.map((child, index) => {React.cloneElement(child, {key: index})})}
</div>
)
}
}
my page.js
class R1 extends React.Component {
render() {
return (
<div className="r1">
<h1>level1</h1>
</div>
);
}
}
class R2 extends React.Component {
render() {
return (
<div className="r2">
<h1>level2</h1>
</div>
);
}
}
my main.js
important * as Page from './page';
class App extends React.Component {
render() {
return (
<div className="r1">
<Page.R+level/>
</div>
);
}
}
Skip getInitialState,
I want to dynamic render with level.
I try React.renderComponent(<Page.R+this.state.level />, document.body);
It's not working with failed: SyntaxError
Is there more easily way? or is dynamic render available?
thanks
Not sure how you are exporting your Components so there is an assumption here, generally it is convention to put them in different files.
You can render in your parent component using an if statement inside JSX like this:
class App extends React.Component {
render() {
var renderPage;
if (something) {
renderPage = <PageOne />;
} else {
renderPage = <PageTwo />;
}
return (
<div>
{renderPage}
</div>
);
}
}
main.js can be modified like this to achieve what you want
import * as Page from './page';
class App extends React.Component {
render() {
const level = 2;
return (
<div className="r1">
{/*You use loop over list to get value of level and render all the pages*/}
{React.createElement(Page[`R${level}`], null)}
</div>
);
}
}
Page is an object and we are trying to access the pages and rendering the component name which is in string type.