React.js - unable to get the specific prop from a component - javascript

so ,i have hard coded the state of the parent component and after passing it in the child component i am unable to retrieve it the child component.
and on the other hand if i pass any other other prop other than the state it works.
this is the child component:
import React from 'react';
import './searchresults.css'
class SearchResults extends React.Component {
render(){
let searchresults= this.props.searchresults;
return(
<div className= "searchresults">
<h2>Weather</h2>
<h3>Temprature:{searchresults.main.temp} </h3>
<h3>Temperature minimum: 25 degrees</h3>
<h3>Temperature maximum: 40 degrees</h3>
<h3>Humidity: 81% </h3>
</div>
)
}
}
export default SearchResults;
this is the parent component:
import React from 'react';
import './App.css';
import SearchBar from '../searchbar/searchbar'
import SearchResults from '../SearchResults/searchresults'
class App extends React.Component {
constructor(props){
super(props)
this.state = {
searchresults:[{"coord":{"lon":-0.13,"lat":51.51},"weather":[{"id":300,"main":"Drizzle","description":"light intensity drizzle","icon":"09d"}],"base":"stations",
"main":{"temp":280.32,"pressure":1012,"humidity":81,"temp_min":279.15,"temp_max":281.15
},"visibility":10000,"wind":{"speed":4.1,"deg":80},"clouds":{"all":90},"dt":1485789600,"sys":{"type":1,"id":5091,"message":0.0103,"country":"GB","sunrise":1485762037,"sunset":1485794875},"id":2643743,"name":"London","cod":200}]
}
}
render(){
return (
<div className="App">
<header className="App-header">
<h1>Wanderer</h1>
</header>
<SearchBar />
<SearchResults searchresults ={this.state.searchresults}
/>
</div>
);
}
}
export default App;
and this the error i get:
TypeError: Cannot read property 'temp' of undefined
SearchResults.render
F:/rishit/wanderer/src/components/SearchResults/searchresults.js:18

Since searchresults in the parent with one item you could pass it like :
<SearchResults searchresults ={this.state.searchresults[0]} />

searchResults is an arrray it should be searchresults[0].main.temp
<h3>Temprature:{searchresults[0].main.temp} </h3>

Here, searchresults is an array. You need to provide index to access an element.
You can use searchresults[0].main.temp but that is not the best way and not a solution if searchresults had multiple elements. I would do it in the following way.
import React from 'react';
import './searchresults.css'
class SearchResults extends React.Component {
render(){
return(
this.props.searchresults.map((searchResult) => (
<div className= "searchresults">
<h2>Weather</h2>
<h3>Temprature:{searchResult.main.temp}</h3>
<h3>Temperature minimum: 25 degrees</h3>
<h3>Temperature maximum: 40 degrees</h3>
<h3>Humidity: 81% </h3>
</div>
))
)
}
}
I hope it works.

Related

ReactJS - document.querySelectorAll() with lazy component

I am having a problem with my React application.
When I try to retrieve a list of selectors, I am unable to retrieve the ones in the lazy component.
In my component, my variable "length" only counts selectors of the class.
She counts 6 instead of 7.
Can you help me solve my problem?
App.js
import React, { Suspense, lazy } from 'react';
import { Switch, Route } from 'react-router-dom';
import AppFront from './AppFront';
import Mouse from './component/Mouse';
import './App.css';
const LazyComponentTwo = lazy(() => import('./component/ComponentTwo'));
function App() {
return (
<div className="App">
<Mouse />
<Switch>
<Suspense fallback={<div>Loading...</div>}>
<Route exact path="/" component={AppFront} />
<Route path="/component-two" component={LazyComponentTwo} />
</Suspense>
</Switch>
</div>
);
}
export default App;
AppFront.jsx
import React, { Component } from 'react';
import ComponentOne from './component/ComponentOne';
class AppFront extends Component {
render() {
return (
<div className="AppFront">
<ComponentOne />
</div>
);
}
}
export default AppFront;
ComponentOne.jsx
import React, { Component } from 'react';
class ComponentOne extends Component {
render() {
return (
<div className="ComponentOne">
<p className="text">Hello, this text contains a class name.</p>
<p className="text">Hello, this text contains a class name.</p>
<p className="text">Hello, this text contains a class name.</p>
<p className="text">Hello, this text contains a class name.</p>
<p className="text">Hello, this text contains a class name.</p>
<p className="text">Hello, this text contains a class name.</p>
</div>
);
}
}
export default ComponentOne;
ComponentTwo.jsx
import React, { Component } from 'react';
class ComponentTwo extends Component {
render() {
return (
<div className="ComponentTwo">
<p className="text">Hello, this text contains a class name.</p>
</div>
);
}
}
export default ComponentTwo;
Mouse.jsx
import React, { Component } from 'react';
class Mouse extends Component {
componentDidMount() {
const length = document.querySelectorAll(".text");
console.log(length); // Output : 6, and not 7
}
render() {
return (
<div className="Mouse">
</div>
);
}
}
export default Mouse;
I would think that this would just be the expected behaviour in this case.
Because the ComponentTwo is displayed on a different route /component-two, and hence not loaded yet, the length of the array returned from the querySelectorAll should indeed be 6.
If in case you want that to be selected at the time of calling the componentDidMount(), you could try not lazy loading the component.

Having some problem on using map() method on my react application

In my app i have an initial state in a component App.js it's an array of objects
Here is App.js code:
import React, { Component } from 'react';
import './App.css';
import { render } from '#testing-library/react';
// Import Used Components
import SearchBar from '../SearchBar/SearchBar';
import Playlist from '../PlayList/PlayList';
import SearchResults from '../SearchResults/SearchResults';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
searchResults: [{name: 'name1',artist: 'artist1',album: 'album1',id: 1},
{name: 'name2',artist: 'artist2',album: 'album2',id: 2}]
};
}
// Adding JSX to App Component
render() {
return (
<div>
<h1>Ja<span className="highlight">mmm</span>ing</h1>
<div className="App">
<SearchBar />
<div className="App-playlist">
<SearchResults searchResults={this.state.searchResults} />
<Playlist />
</div>
</div>
</div>
);
}
}
export default App;
I passed this initial state as a prop called searchResults to another component named .
Here is searchResults.js code :
import './SearchResults.css';
import TrackList from '../TrackList/TrackList';
class SearchResults extends React.Component {
render() {
return (
<div className="SearchResults">
<h2>Results</h2>
<TrackList tracks={this.props.searchResults}/>
</div>
);
}
}
export default SearchResults;
then I used passed this prop to another component called TrackList
here is TrackList.js code:
import React from 'react';
import './TrackList.css';
import Track from '../Track/Track';
class TrackList extends React.Component {
render() {
return(
<div className="TrackList">
{
this.props.tracks.map(track => {
return <Track track={track} key={track.id} />;
} )
}
</div>
);
}
}
export default TrackList;
In Track.js I want to map through this initial state array to render a component called Track
here is the Track.js code:
import React from 'react';
import './Track.css';
class Track extends React.Component {
renderAction() {
if (this.props.isRemoval){
return <botton className='Track-action'>-</botton>;
} else {
return <botton className='Track-action'>+</botton>;
}
};
render() {
return (
<div className="Track">
<div className="Track-information">
<h3>{this.props.track.name}</h3>
<p>{this.props.track.artist} | {this.props.track.album}</p>
</div>
<button className="Track-action">{this.renderAction}</button>
</div>
);
}
}
export default Track;
But something is wrong !! I keep getting this error:
TypeError: Cannot read property 'map' of undefined
Here is searchBar.js component code:
import React from 'react';
import './SearchBar.css';
class SearchBar extends React.Component {
render() {
return (
<div className="SearchBar">
<input placeholder="Enter A Song, Album, or Artist" />
<button className="SearchButton">SEARCH</button>
</div>
);
}
}
export default SearchBar;
HERE LINK TO THE PROJECT WITH THE SAME ERROR ON SANDBOX
https://codesandbox.io/s/upbeat-dawn-lwbxb?fontsize=14&hidenavigation=1&theme=dark
Change your TrackList component to this:
class TrackList extends React.Component {
render() {
return (
<div className="TrackList">
{this.props.tracks && this.props.tracks.map(track => {
return <Track key={track.id} track={track}/>
})}
</div>
);
}
}
You can't map through this.props.tracks if it is undefined.
The && (AND operator) is a concise way to conditionally render in React. You can think of it like a simple if statement: If the expression on the left is true, then do x.
I'll also expand on why the this.props.tracks was undefined in a certain instance in your case.
The reason that this problem is happening is your Playlist component. If you uncomment this component from your App you will notice your original code will work.
This is because your PlayList component, like your SearchResults component, also renders your TrackList component. The problem is you haven't passed your state and props down to TrackList like you did with your SearchResults component.
So an alternative solution would be to pass your state and props down from PlayList to TrackList:
App.js
// ...
<SearchResults searchResults={this.state.searchResults} />
<Playlist searchResults={this.state.searchResults}/>
// ...
PlayList.js
// ...
<TrackList tracks={this.props.searchResults}/>
// ...

ReactJS - State change is not observed in divs wrapped in sub component

I have the following react class. In it I'm using other react components. I'm new to React so I think I'm misunderstanding how state scope works. When menuClicked() is called, the outermost div's class will change but the innermost div's class does not. Can someone explain why?
import React, {Component} from 'react';
import Row from '../components/grid/Row.js'
import Cell from '../components/grid/Cell.js'
export default class HeaderBar extends Component {
state = {
menuOpen: false
};
constructor(props) {
super(props);
this.menuClicked = this.menuClicked.bind(this);
}
menuClicked() {
this.setState({menuOpen: !this.state.menuOpen})
};
render() {
return (
<div
className={`header-wrap ${this.state.menuOpen ? 'open' : ''}`}
>
<Row>
<Cell
c={1}
mc={12}
>
<div className={`platform-name ${this.state.menuOpen ? 'open' : ''}`}>The Platform Name</div>
</Cell>
<Cell>
<div onClick={this.menuClicked}></div>
</Cell>
</Row>
</div>
)
}
}
Added by popular demand
import React, {Component} from 'react';
export default class Row extends Component {
constructor(props) {
super();
this.children = props.children;
}
render() {
return (
<div className="r">
{this.children}
</div>
)
}
}
And the Cell class
import React, {Component} from 'react';
export default class Cell extends Component {
constructor(props) {
super();
this.props = props;
}
render() {
return (
<div
className={`c${this.props.c}`}
>
{this.props.children}
</div>
)
}
}
Problem in Row component constructor, you do this.children = props.children;, then you render this.children.
Remember constructor is called only once. So this.children is assigned once with initial value and never get updated afterwards. It’s a stale reference!
Don’t do that, just render this.props.children

TypeError: Cannot read property 'map' of undefined, while trying to .map() an array passed through props

I am not sure why I am getting TypeError: Cannot read property 'map' of undefined here:
I am trying to pass an array down from App.js to => SearchResult.js to => TrackList.js
TrackList.js:
import React from 'react';
import Track from '../Track/Track'
import '../TrackList/TrackList.css';
class TrackList extends React.Component {
render() {
return (
<div className="TrackList">
{this.props.tracks.map(track => {
console.log(track);
<Track track={track} />}
)}
</div>
);
}
}
export default TrackList;
the console.log(track) above returns an array of objects as expected, I think that makes sure that this.props.tracks is an array.
App.js:
import React, { Component } from 'react';
import './App.css';
import SearchBar from './Components/SearchBar/SearchBar';
import SearchResults from './Components/SearchResults/SearchResults';
import Playlist from './Components/Playlist/Playlist';
const track = {
name: "Tiny Dancer",
artist: 'Elton John',
album: 'Madman Across The Water'
};
const tracks = [track, track, track];
class App extends Component {
constructor (props) {
super(props);
this.state = {'searchResults': tracks};
}
render() {
return (
<div>
<h1>Ja<span className="highlight">mmm</span>ing</h1>
<div className="App">
<SearchBar />
<div className="App-playlist">
<SearchResults searchResults={this.state.searchResults}/>
<Playlist />
</div>
</div>
</div>
);
}
}
export default App;
SearchResults.js:
import React from 'react';
import '../SearchResults/SearchResults.css';
import TrackList from '../TrackList/TrackList';
class SearchResults extends React.Component {
render() {
return (
<div className="SearchResults">
{/* {console.log(this.props.searchResults)} */}
<h2>Results</h2>
<TrackList tracks={this.props.searchResults}/>
</div>
);
}
}
export default SearchResults;
I also tried using props to pass the array from App.js (instead of state) but I got the same error.
sometimes react will render the app before your props loaded. this especially happens if you're getting props form an api call. react will throw an error if that happens. here's a work around:
import React from 'react';
import Track from '../Track/Track'
import '../TrackList/TrackList.css';
class TrackList extends React.Component {
constructor(props){
super(props)
this.state={}
}
render() {
//es6 syntax. this will allow the app to render and then replace the
//tracks variable with this.props.tracks when the props are ready
//this check if this.props.tracks exist and if it doesn't it will
//assign the variable to an empty array. then .map will not be
//called on an undefined variable.
let tracks = this.props.tracks ? this.props.tracks : [];
return (
<div className="TrackList">
{tracks.map(track => {
console.log(track);
<Track track={track} />}
)}
</div>
);
}
}
export default TrackList;

react - add icons to header inside component

i am currently trying to solve a react problem.
i want to be able to add icons to a container called SalesChannels.
here is the code to the salesChannels page: (JSX)
import React, { Component } from 'react';
import PageContent from 'components/PageContent';
import IBox from 'components/IBox';
export default class SalesChannelsPage extends Component {
constructor(props) {
super(props);
this.state = {
rows: []
}
}
render() {
return (
<PageContent header="Salgskanaler">
<IBox title="Salgskanaler">
</IBox>
</PageContent>
);
}
}
As you can see, i have added a component called IBox. this should be reusable
it looks like this:
import React, {Component} from 'react';
import IBoxTools from './IBoxTools'
export default class IBox extends Component {
render() {
return(
<div className="ibox">
<div className="ibox-title">
{this.props.title}
//this is where the icon should be rendered in the dom
</div>
<div className="ibox-content">
{this.props.children}
</div>
</div>
);
}
}
i have also created another component called IBoxTools - this contains the actual icon / "i" tag:
import React, {Component} from 'react';
export default class IBoxTools extends Component {
render() {
let icon;
if(this.props.icon) {
icon = (
<a title={this.props.title}>
<i onClick={() => this.iconClicked()} className={`pull-right ${this.props.icon}`}></i>
</a>
);
}
return icon;
}
iconClicked() {
console.log('icon clicked')
}
}
So what i am trying to do is add multible icons to the SalesChannels page, inside the IBox tag, without making the IBox component dependent on it.
I hope you can help. Thanks!
You can pass components or arrays of components in props just like children
<IBox
title="Salgskanaler"
icons={[
<IBoxTools key="icon1" icon="foo" />,
<IBoxTools key="icon2" icon="bar" />
]}
>
{/* normal children here */}
</IBox>
Then inside IBox you write { this.props.icons } which will render the icons (or whatever else) if you pass it in.. otherwise will display nothing if the prop is undefined.
You could just use a condition if you don't want to display the icon every time. If I understand what you're attempting to do ...
import React, {Component} from 'react';
import IBoxTools from './IBoxTools'
export default class IBox extends Component {
render() {
return(
<div className="ibox">
<div className="ibox-title">
{this.props.title}
//this is where the icon should be rendered in the dom
{(condition) ? <IBoxTools /> : ""}
</div>
<div className="ibox-content">
{this.props.children}
</div>
</div>
);
}
}
Or if you need to do it multiple times, like you said, then I would use underscore.js or something like it that has a map function.
{_.map(icons, function(icon) {
return (
<IBoxTools />
)
})}
Or some combination of the two.

Categories