cannot read property 'map' of undefined in React jsx - javascript

I am learning react by going through a react tutorial and i am getting a map undefind error. What should i do?
I am trying to iterate over the array to display the data of the array in the player component but i am still getting this error. i tried searching online and looking through at other map undefined error on stack overflow but none is like my problem that i am having.
const players = [
{
name: "Guil",
score: 50
},
{
name: "Treasure",
score: 85
},
{
name: "Ashley",
score: 95
},
{
name: "James",
score: 80
}
];
const Player = (props) => {
return (
<div className="player">
<span className="player-name">
{props.name}
</span>
<Counter score={props.score} />
</div>
);
}
const App = (props) => {
return (
<div className="scoreboard">
<Header
title="Scoreboard"
totalPlayers={4}
/>
{/* Players list */}
{props.initialPlayers.map(player =>
<Player
name={props.name}
score={props.score}
/>
)}
</div>
);
}
ReactDOM.render(
<App initialPlayers={ players}/>,
document.getElementById('root')
);
export default App;

Considering you didn't give us the error message, I can't be sure of what is actually undefined, although I doubt that map is undefined.
In the snippet below, you're trying to access props.name and props.score, which don't exist in the context. You've called the player player within the map callback and need to access it as such.
i.e. change props.name and props.score to player.name and player.score.
{props.initialPlayers.map(player =>
<Player
name={props.name} // player.name
score={props.score} // player.score
/>
)}

Looks like cubrr's comment might have identify the issue that you are running into. You are probably getting the error here:
const App = (props) => {
return (
<div className="scoreboard">
<Header
title="Scoreboard"
totalPlayers={4}
/>
{/* Players list */}
{props.initialPlayers.map(player =>
<Player
name={props.name}
score={props.score}
/>
)}
</div>
);
}
since props.name = undefined, you are trying to render something that does not exist. You will need to change it to:
{props.initialPlayers.map(player =>
<Player
name={player.name}
score={player.score}
/>
)}
Hope that helps.
React is relatively good at providing error logs for you, please be sure to take a look at error logs and it will tell you which line the error is occurring on.

Related

onClick is not working in my react component

onClick (handleRecipeAdd), onClick (handleRecipeDelete) is not working
I am learning react recently and I need some help. Below I have pasted all the code.
App.js code:
const [recipes, setRecipes] = useState(sampleRecipes)
function handleRecipeAdd(){
const newRecipe = {
id: uuidv4(),
name: 'New',
servings: 1,
cookTime: '1:00',
instructions: 'Instr.',
ingredients: [{id: uuidv4(), name: 'Name', amount: '1 Tbs'}]
}
setRecipes([...recipes, newRecipe])
}
function handleRecipeDelete(id){
setRecipes(recipes.filter(recipe=>recipe.id !== id))
}
return (
<RecipeList recipes={sampleRecipes} handleRecipeAdd={handleRecipeAdd} handleRecipeDelete={handleRecipeDelete}/>
)
}
RecipeList Code
export default function RecipeList({recipes, handleRecipeAdd, handleRecipeDelete}) {
return (
<div className='recipe-list'>
<div>
{recipes.map(recipe => {
return (
<Recipe key={recipe.id} {...recipe} handleRecipeDelete={handleRecipeDelete}/>
)
})}
</div>
<div className="recipe-list__add-recipe-btn-container">
<button onClick={handleRecipeAdd} className='btn btn--primary'>Add Recipe</button>
</div>
</div>
)
}
Recipe Code
export default function Recipe({handleRecipeDelete}) {
return (
<div className='recipe'>
<div className='recipe__header'>
<button className='btn btn--primary mr-1'>Edit</button>
<button onClick={()=>handleRecipeDelete(id)} className='btn btn--danger'>Delete</button>
</div>
</div>
)
}
I am not getting any idea, I have searched a lot and didn't find any mistake. So help me out to fix this.
You are using props drilling here, which is not a good way but you are learning so it's ok, after props try to learn React Context API, it will help you to handle use-cases from any components.
coming to your problem
in App.js you are passing props like this <RecipeList recipes={sampleRecipes} .../> but it should like this <RecipeList recipes={recipes} .../>
why recipes because this is the original state which will have a default value which will update or modified in the future.
for deleting or filtering data you need an id or index, right? but ID is best.
you are passing the function with an id but you don't have an id there for a pass, you have to pass the id to that component.
your code <Recipe key={recipe.id} {...recipe} handleRecipeDelete={handleRecipeDelete}/>
New code replaces {...recipe} -> id={recipe.id}
<Recipe key={recipe.id} id={recipe.id} handleRecipeDelete={handleRecipeDelete}/>
and on the Recipe component receive id as an argument Recipe({id, handleRecipeDelete}), and your code will work fine.
<button onClick={(event)=>handleDelete(event.targrt.id)}>Delete</button>

useStates seem as undefined on props

I am trying to get some datas from child to parent. There is a way I usually do, and it totally works. But for one page I used:
<Link to={{
pathname: `/productBuy`,
state: { product, iconClick }
}}>
and when I send another prop from App.js to productBuy page, it's shown under product and it's undefined.
Codes from App.js :
const [productInformation, setProductInformation] = useState([]);
<Route path="/productBuy" render={props => <ProductBuy {...props} productInformation {productInformation} setProductInformation={setProductInformation} />} />
productBuy.js :
const ProductBuy = (productInfo, {productInformation,setProductInformation}) => {
return (
<div className="productBuy">
<div className="productBuyContainer">
<ProductLeft productInfo={productInfo.location.state} />
<ProductRight productInfo={productInfo.location.state} productInformation={productInformation} setProductInformation={setProductInformation}/>
</div>
</div>
);
}
When I console.log, my props are shown under product object as undefined. and when I invoke a function, an error appears: ProductRight.js:51 Uncaught TypeError: setProductInformation is not a function
Is there a way to solve this problem?
First of all you're missing the = after productInformation in the render prop:
<ProductBuy {...props} productInformation={productInformation} setProductInformation={setProductInformation} />
And the second issue is that you're unpacking the props incorrectly. Both productInformation and setProductInformation are available in the props argument (the first positional argument) in your function, but you're unpacking it in the second argument instead:
// INCORRECT
const ProductBuy = (productInfo, {productInformation,setProductInformation}) => { ... }
You can unpack it from the productInfo argument, which is an object that holds all the props:
const ProductBuy = (productInfo) => {
const { productInformation, setProductInformation } = productInfo;
return (
<div className="productBuy">
<div className="productBuyContainer">
<ProductLeft productInfo={productInfo.location.state} />
<ProductRight productInfo={productInfo.location.state} productInformation={productInformation} setProductInformation={setProductInformation}/>
</div>
</div>
);
}
You can also choose to unpack it at the top level:
const ProductBuy = ({ location, productInformation, setProductInformation }) => {
return (
<div className="productBuy">
<div className="productBuyContainer">
<ProductLeft productInfo={location.state} />
<ProductRight productInfo={location.state} productInformation={productInformation} setProductInformation={setProductInformation}/>
</div>
</div>
);
}
Add equal sign when passing the productInformation to props seems you forgot that in App.js
<Route path="/productBuy" render={props => <ProductBuy {...props} productInformation={productInformation} setProductInformation={setProductInformation} />} />

I am getting an Error: React.Children.only expected to receive a single React element child in my index.js page. Is there a workaround

Index.js code here
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
I am guessing the error is not comming from the code above and neither is it comming the App.js code.
App.js code here
function App() {
return (
<div className="App">
<header className="App-header">
<AppNavbar/>
<ShoppingList/>
</header>
</div>
);
}
Here's an excerpt from ShoppingList.js. Hope this is of help:
I think this is where the problem originates because I changed items.map this.state.items.map and the error was, items.map is not defined.
class ShoppingList extends Component {
state = {
items: [
{ id: uuid(), name: 'Eggs'},
{ id: uuid(), name: 'Milk'},
{ id: uuid(), name: 'Apples'},
{ id: uuid(), name: 'Water'},
]
}
render() {
const items= this.state;
return(
<container>
<Button
color="dark"
style={{marginBottom : '2rem'}}
onClick={() => {
const name = prompt("Enter item");
if (name) {
this.setState( state => ({
items: [...state.items, {id: uuid(), name}]
}));
}
}}
>Add Item</Button>
<ListGroup>
<TransitionGroup className="shopping-list">
{this.state.items.map(({ id, name}) => (
<CSSTransition key="{id}" timeout="500" classNames="fade">
</CSSTransition>
))}
</TransitionGroup>
</ListGroup>
</container>
)
}
}
I have checked many other errors similar to this but without any success. Does anyone have a solution for this?
Firstly, as per react-transition-group documentation, you will need to put the stuff you need transition inside <CSSTransition>. So in your case, put your ListGroup.Item and Button inside CSSTransition.
Also, you have used wrong key(string) in <CSSTransition key="{id}". So use provide unique key - like this - <CSSTransition key={id}
Working copy of your code is here:
https://codesandbox.io/s/wild-snow-gwilb?file=/src/ShoppingList.js
Try putting
<AppNavbar/>
<ShoppingList/>
under
<div></div> tag as header might need single element under it.

Gatsby works fine during development but throws error during build

I am passing data from one page to another in gatsby. First page code:
let state = {book: book, src: src}
return (
<div className="book__holder">
<Link to="/pdf/" state={state}>
<Card
hoverable
style={{ width: 240 }}
cover={<img alt={book}
src={url}
/>}
>
<Meta
title={book}
description={faculty+" "+year+"-"+part}
/>
</Card>
</Link>
</div>
This data is used in pdf page as:
const PDFPage = props =>{
return (
<React.Fragment>
<SEO title={props.location.state.book} />
<NavBar></NavBar>
<Embed src={props.location.state.src} type="application/pdf">
</Embed>
</React.Fragment>
)}
export default PDFPage
Everything is fine when using gatsby develop but when i use gatsby build it throws following error:
error Building static HTML for pages failed
See our docs page on debugging HTML builds for help https://gatsby.app
/debug-html
11 | return (
12 | <React.Fragment>
> 13 | <SEO title={props.location.state.book} keywords={[`gatsby`,
`application`, `react`]} />
| ^
14 | <NavBar></NavBar>
15 | <Embed src={props.location.state.src} type="application/pdf">
</Embed>
16 |
WebpackError: TypeError: Cannot read property 'book' of undefined
- pdf.js:13 PDFPage
lib/src/pages/pdf.js:13:38
Can anyone help me please?
Gatsby will throw error during production build, since location is not available during server-side rendering.
One way to make sure the build doesn't throw an error is to:
Check for the window in componentDidMount
Map the location prop to state
Render the value from your state instead of directly from props
In componentDidMount()
componentDidMount() {
if (typeof window === 'undefined') {
return;
}
this.setState(() => ({ playerName: this.props.location.state.playerName }));
}
In render()
render() {
return <div>{this.state.playerName}</div>;
}
credit to this thread, How to get previous url in react gatsby
Sometimes you’ll want to pass data from the source page to the linked page. You can do this by passing a state prop to the Link component... The linked page will have a location prop containing a nested state object structure containing the passed data.
Passing Props to Link targets
While the following demo is not actually using gatsby, it is using reach router (and gatsby uses reach router under the hood).
import React from "react";
import { render } from "react-dom";
import { Router, Link } from "#reach/router";
const App = () => {
let state = {
name: 'Ron',
book: {
title: 'Harry Potter and the Deathly Hallows',
author: 'J. K. Rowling',
progress: '80%'
}
}
return (
<div>
<h1>App</h1>
<nav>
<Link to="/" state={state}>Home</Link>{" "}
<Link to="dashboard" state={state} >Dashboard</Link>
</nav>
<Router>
<Home path="/" />
<Dashboard path="/dashboard" />
</Router>
</div>
)};
const Home = ({location}) => (
<div>
<h2>Welcome { location.state.name }</h2>
<p></p>
</div>
);
const Dashboard = ({location}) => (
<div>
<h2>Dashboard</h2>
<p>Hi { location.state.name }.</p>
<p>You have read { location.state.book.progress } of { location.state.book.title } by { location.state.book.author }.</p>
</div>
);
render(<App />, document.getElementById("root"));
Stackblitz

How to Retrieve and Render Data from Firebase using ID/Key (with React)?

I’m trying to access data from the Firebase server and then proceed to open a view page of the object. My routing is working for sure I think.
The index component I want the clicked post to link from is this:
renderPosts() {
return _.map(this.state.posts, (post, key) => {
return (
<div key={key} className="thumbnail">
<h2>
<Link to="/view/posts/{post}">
{post.title}
</Link>
</h2>
<p>{post.body}</p>
</div>
);
});
}
I tried to link to the post cause I figured it work based on the componentDidMount used to build that function. And I imported the view component into it as well.
The app.js page is as this:
<BrowserRouter>
<div>
<div>
<Nav/>
</div>
<Switch>
<Route path='/' exact component={List}/>
<Route path='/new' component={NewPost}/>
<Route path='/view' component={View}/>
</Switch>
</div>
</BrowserRouter>
</div>
);
}
}
And the view.js page is as follows:
componentWillMount(){
let postRef = database().ref('posts').orderByKey().limitToLast(100);
postRef.on('value', snapshot => {
let post = { title: snapshot.title, id: snapshot.key };
this.setState({ posts: [post].concat(this.state.posts) });
});
console.log(postRef);
}
}
render() {
return (
<div >
</div>
);
}
}
Sorry. It’s a bit bare now cause I removed everything I have tried. I used a couple articles and videos to try to figure it out but nothing worked. The original lifecycle method and constructor I used for the index page however is this:
constructor(props){
super(props);
this.state = {
title: '',
body: '',
posts:{}
};
this.onInputChange = this.onInputChange.bind(this);
this.onHandleSubmit = this.onHandleSubmit.bind(this);
}
and
componentDidMount(){
database.on('value', snapshot => {
this.setState({
posts: snapshot.val()
});
});
}
I’m sorry, I know it is a lot to get through but I thought I should cover everything that might be useful. But to sum up: My issues are how to retrieve the post from the database and then add the key that Firebase automatically makes to the link and thus render it in a new page.
Ps. My database is exported as this
export const database = firebase.database().ref('/posts’);
I don't understand the question but it sounds like the post key contains the value you want for the link. If that's the case then try...
renderPosts(){
return Object.keys(this.state.posts).map((post, index)=>(
<div key={index} className="thumbnail">
<h2>
<Link to={`/view/posts/${post}`}>
{this.state.posts[post].title}
</Link>
</h2>
<p>{this.state.posts[post].body}</p>
</div>
)}
);
then you should just be able to call your renderPosts function in your render method.
render() {
return (
<div >
{renderPosts()}
</div>
);
}
It might take a little while to get the post data if you're calling firebase so only call the render method when the post data shows up.
render() {
return (
<div >
{this.state.posts && renderPosts()}
</div>
);
}

Categories