I'm passing a map to all my posts variable so that all my posts can appear as a single post, but it kept bringing up the error
I have tried solving it using the Reactjs Documentation from the react website, it shows almost the same code as mine.
import PropTypes from 'prop-types';
import PostItem from './PostItem';
class PostFeed extends Component {
render() {
const { posts } = this.props;
const list = posts.map((post) => <PostItem
key={post._id}
posts={post}
/>
);
return (
{list}
);
}
}
PostFeed.propTypes = {
posts: PropTypes.array.isRequired
};
export default PostFeed;
I expect every posts to appear as a single post from the postItem component
The error means, when your PostFeed mounts for first time at that time props are not available, so the error.
You can check if data available, like,
let list = "Loading...";
if(posts && posts.length > 0){
list = posts.map((post) => <PostItem key={post._id} posts={post} /> );
}
posts is probably result of an async action and its value is not available at the time that your function is doing its job. So it should have a default value or be checked before that has a value.do this:
if(this.props.posts && Array.isArray(this.props.posts) && this.props.posts.length > 0)
//then map
Related
I have a problem with reading {find}.
The problem is in ProductDetail.js.
First, click on the products link than on any product to see details.
TypeError: Cannot read properties of null (reading 'find')
https://codesandbox.io/s/react-router-product-detail-pages-dynamic-links-forked-y1o0n?file=/src/ProductDetail.js:418-429
You've done some mistakes over there in your ProductDetail.js file.
First:
You can use useEffect hook to check and compare if there is a matching id or not.
Second:
You can use useState hook to store the thisProduct and update the thisProduct value by calling setThisProduct and use it in the JSXElement.
This is always a best practice to use the state for data set and get.
Here is more about React.Hooks
Third:
Price is a Object and you can't render your object like that, so use the key instead of object while rendering. like this: {thisProduct?.price?.current?.value}
You can learn more about optional chaining
Fourth:
productId which you're getting from useParams is a string type, and your productId from sneakers is a number type. So you need to change your productId to number while comparing like this: Number(productId)
Learn about Numbers in Js
Here is the complete code of yours:
// ProductDetail.js
import React, { useContext, useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import { StateContext } from "./GlobalContext";
function ProductDetail() {
const { productId } = useParams();
const { sneakers } = useContext(StateContext);
const [thisProduct, setThisProduct] = useState({});
useEffect(() => {
if (sneakers) {
const findProduct = sneakers.find((product) => {
return product.id === Number(productId);
});
console.log("findproduct", findProduct);
setThisProduct(findProduct);
}
}, [productId, sneakers]);
return (
<div>
{thisProduct && (
<>
<h1>{thisProduct?.name}</h1>
<p>Price: {thisProduct?.price?.current?.value}</p>
<p>{thisProduct?.description}</p>
</>
)}
</div>
);
}
export default ProductDetail;
completely check your state and props, it is not providing valid data to child component
<StateContext.Provider value={{ sneakers }}>
{console.log(sneakers, "== thisProduct")}
{children}
</StateContext.Provider>
console will show your data, it coming null so that is the issue
I have a project where I used redux-saga to make an API call with axios and return the data to the store, which then I mapStateToProps using redux and now I want to map() it and show it on my DOM, but I'm getting "undefined".
Two things keep happening:
either the data doesn't get called in time and the render happens to fast so it says its undefined.
i get map() is not a function or for {blog.id} -- id is undefined.
When I console.log(blogs) i see my array of blogs so I'm not sure what I'm doing wrong. Is it because blogs is an array and so I need to do some kind of for loop to go through the each item and then map it?
Here is my main chunk of code and the console log
import React, {Component} from 'react';
import {connect} from 'react-redux'
import {loadBlogs} from '../../store/actions/blogActions'
class Bloglist extends Component {
componentDidMount() {
this.props.loadBlogs();
}
render() {
const {blogs} = this.props
console.log(blogs)
return (
<div>
<h1>{blogs.map(blog => (
<span>{blog.id}</span>
))}</h1>
</div>
)
}
}
const mapStateToProps = blogs => ({
blogs
})
const mapDispatchToProps = dispatch => ({
loadBlogs: () => dispatch(loadBlogs()),
})
export default connect(mapStateToProps, mapDispatchToProps)(Bloglist)
here is a console log example and an error:
Uncaught TypeError: blogs.map is not a function
this is when I just comment out the map() lines and just return a "hello", this console.log is showing me that the data is coming back
Bloglist.js:14 (3) [{…}, {…}, {…}]
Please let me know if you want any more samples or info. It's really important to get this done so any help would be appreciated! Thanks!
There can be 2 issues.
Please cross check the type of blogs, it should be array as map method works only on array.
You have to check for array's length before mapping it. As map method doesn't works on empty array.
Try this code --
<div>
<h1>{blogs && blogs.length > 0 ? blogs.map(blog => (
<span>{blog.id}</span>
)) : null}</h1>
</div>
At the beginning, your blogs is not an Array.
You should to update your reducer initialState, set blocks to be an empty array as default, just like
in reducer.js
const initialState = {
blogs: [],
};
export default (state = initialState, action) => {
switch(action) {
case....
default:
return { ...state };
}
}
Or, you also should check the blogs before rendering.
Array.isArray(blogs) && blogs.map(item => (
<div>
{// item details goes here}
</div>
))
use ? to handle this error. mostly probably the error is coming from the saga. you have to provide the code better suggest a solution.
<div>
<h1>{blogs?.map(blog => (
<span>{blog.id}</span>
))}</h1>
</div>
Try like this.
class Example extends Component {
state:{}
render(){
//.....code
}
}
I have an issue regarding react and I was hoping i could get some help. I will try my best to explain my situation and i will provide examples where needed.
The situation:
I have this component:
import React , {useState} from 'react';
import axios from 'axios';
import Ui from './UI';
function App() {
const [weather, setWeather] = useState({});
const [query, setQuery] = useState({query : ''});
const handleSubmit = (e) => {
e.preventDefault();
axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${query.query}&units=metric&appid=appid`)
.then(res => {
setWeather({data: res.data})
});
};
const handleChange = (e) => {
setQuery({query:e.target.value});
};
return (
<div className="App">
<form onSubmit={handleSubmit}>
<input type="text" onChange = {handleChange}/>
<input type="submit" value = 'Search!'/>
</form>
<Ui weather ={weather}/>
</div>
);
}
export default App;
It's fetching data from the openweather API. When everything is set, I pass the Weather data to the presentational component named "Ui".
The data weather object that i pass down to the Ui has properties. One of these properties looks like 'weather.data.main'. When I try to access this in my presentational component I get an error.
TypeError: Cannot read property 'main' of undefined
But i am sure main exists. How is this possible ?
here's my presentational component :
import React , {useState} from 'react';
import axios from 'axios';
function Ui(weather) {
console.log(weather.data.main);
return (
<div className="Ui">
<h2>{}</h2>
</div>
);
}
export default Ui;
First issue
weather is a property of prop passed to Ui component so you need to either
destructure it
function Ui({ weather }) {
console.log(weather.data.main);
return (
<div className="Ui">
<h2>{weather.data.main}</h2>
</div>
);
}
Or use props.weather.data.main.
function Ui(props) {
console.log(props.weather.data.main);
return (
<div className="Ui">
<h2>{props.weather.data.main}</h2>
</div>
);
}
Second issue
TypeError: Cannot read property 'main' of undefined
Now to address the 2nd issue is that, the weather property might not be available at the time it was being passed to Ui component.
There are also two ways to fix this issue.
You can check & display a loading message/gif if the value you'd like to access (weather.data.main) is still unavailable or undefined.
(validating in the child level)
function Ui({ weather }) {
if (weather === undefined ||
weather.data === undefined ||
weather.data.main === undefined)
return <div>Loading weather data...</div>
return (
<div className="Ui">
<h2>{weather.data.main}</h2>
</div>
);
}
Or you can render Ui only when Weather data is available. (It basically depends on where in the component tree you'd like to display the Loading message/gif).
function App() {
// ... rest redacted for brevity
return (
// ... rest redacted for brevity
{weather && weather.data && <Ui weather ={weather}/>}
)
}
That oddly looking && chain instructs that App should display only when weather && weather.data is available.
Instead of having to use if statements I did in the Ui components in #1 above, && is just a short-hand.
Consider this:
import React , {useState} from 'react';
import axios from 'axios';
function Ui({ weather }) {
console.log(weather.data && weather.data.main);
return (
<div className="Ui">
<h2>{}</h2>
</div>
);
}
Note that: weather.data && this will check if weather actually has data, and then checks for the main inside that data.
You have to access weather like this
function Ui({ weather }) {
console.log(weather.data.main);
return (
<div className="Ui">
<h2>{}</h2>
</div>
);
}
Initially weather is equal to {} whiche doesn't have data.main. Hence you can do the following -
{weather.data && <Ui weather ={weather}/>}
This will render Ui only when weather.data is available (not before that).
I've been following this tutorial for ReactJS and have been trying now to convert the simplistic Todo App (just checks off and on items) to React Native. I've been using expo to try it live on my phone and everything.
It all went good, but now I'm trying to add something. Whenever I click the checkbox I want to remove the component related to that item.
My idea was:
Since I'm rendering the TodoItem components from an array of todos,
and whenever I click a checkbox it updates the array as a whole
(looking for a certain id and updating it's completed variable). I can
run through the array and whenever the id is different I return the
todo. This way I returned every todo but the one with matching id to
be rendered.
import React, { Component } from 'react';
import { Alert,Image,StyleSheet, Text,Button, View } from 'react-native';
import TodoItem from './TodoItem'
import todosData from "./todosData"
export default class App extends React.Component {
constructor() {
super()
this.state = {
todos: todosData
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(id) {
this.setState(prevState => {
const updatedTodos = this.state.todos.map( todo => {
if(todo.id !== id) {
return todo
}
})
return {
todos:updatedTodos
}
})
}
render() {
const todoItems = this.state.todos.map( item =>
<TodoItem
key={item.id}
item={item}
handleChange = {this.handleChange}
/>
)
return (
<View style={styles.container}>
{todoItems}
</View>
);
}
}
This gives an error: ' TypeError:undefined is not an object (evaluating 'item.id')', giving at App.js:42:18
I'll also add the code referring to the TodoItem:
import React, { Component } from 'react';
import { Alert,Image,StyleSheet, Text,Button, View } from 'react-native';
import { CheckBox } from 'react-native-elements'
function TodoItem(props) {
return (
<View>
<CheckBox
checked={props.item.completed}
onPress={() => props.handleChange(props.item.id)}
/>
<Text>{props.item.text}</Text>
</View>
);
}
export default TodoItem
I don't understand why this won't work. It feels like I'm deleting the component while still using it (for it to give a undefined), but I don't see where. Since I'm simple updating a list of todos.
How can I do the thing I want?
PS: I seem unable to properly format the first segment of code. I apologize for that!
Try this:
handleChange(id) {
const { todos } = this.state
// filter out the deleted one
const filtered = todos.filter(x => x.id !== id)
this.setState({ todos: filtered })
}
We don't want to alter the state directly, but since .filter() creates a new array, without touching the given array, it is fine to use it. if it was another operation, you'd do something like this:
// create a copy
const newSomethings = [...this.state.somethings]
// do whatever with newSomethings
this.setState({ somethings: newSomethings })
Nothing was returned from render. This usually means a return statement is missing. Or, to render nothing, return null.
I Have an issue related to this message. This is my component that causes the error:
import React from 'react';
import Thumbnail from './Thumbnail';
const AlbumList = ({ results }) => {
let collections = [];
let albums = { };
Object.values(results).map((item, i) => {
if(!collections.includes(item.collectionId)) {
collections.push(item.collectionId);
albums[i] = {id: item.collectionId, cover: item.artworkUrl100}
}
return albums;
});
Object.values(albums).forEach(element => {
return (
<Thumbnail source={element.cover} />
)
})
}
export default AlbumList;
Thumbnail is just a basic Component like:
import React from 'react';
const Thumbnail = ({source}) => {
return(
<div>
<img src={source} alt="album cover"/>
</div>
)
}
export default Thumbnail;
I've been looking for the error like an hour or so.
What am I missing?
Notice that map returns a list while forEach returns undefined.
You don't return anything from your functional Component Plus forEach does not return anything, instead change it to map.
Also you need to set the unique key to Thumbnail component in loop
return Object.values(albums).map((element, index) => {
return (
<Thumbnail key={"Key-"+index} source={element.cover} />
)
})
I would suggest to read this article map vs. forEach