This question already has answers here:
When should I use a return statement in ES6 arrow functions
(6 answers)
Closed 23 days ago.
I want to make a function renderItems so it can be inserted into the return but it does not work
is displayed in the console undefined
if you insert this function into the return all works but I do not want to do so
import React, { useState } from "react";
import { useEffect } from "react";
import PostService from "../../API/PostService";
import Loading from "../loading/Loading";
import "./ItemList.css";
export default function ItemList() {
const [peopleList, setPeopleList] = useState();
const [items, setItems] = useState();
const postService = new PostService();
useEffect(() => {
postService.getAllPeople().then((peopleList) => {
setPeopleList(peopleList);
});
}, []);
const renderItems = (arr) => {
arr.map(({ id, name }) => {
return (
<li className="list-group-item" key={id}>
{name}
</li>
);
});
};
return (
<div>
{!peopleList ? (
<Loading />
) : (
<ul className="item-list list-group">
{console.log(renderItems(peopleList))}
</ul>
)}
</div>
);
}
you just have to return from renderItems
const renderItems = (arr) => {
return arr.map(({ id, name }) => {
return (
<li className="list-group-item" key={id}>
{name}
</li>
);
});
};
Related
I was creating the functionality of pinning and unpinning of particular note, so when the user clicks the thumbtack icon I want that icon of only that particular note changes to a cross icon but when I am clicking on the second notes to pin it then the icon that changed on previous pinned note gets restored to its original form.
I have created the pinning functionality using onPin function but struggling with changing the icon of that particular pinned item.
I want to add icons to pinned items in such a way that previously added close icons stay in their place and do not get updated.
What I tried?
So i created the state variable iconId which is an array so whenever the user clicks pinned icon then new id will be pushed to the iconId array and while displaying the output I put the condition that if the current id is included in iconId array then change icon of all those respective ids in iconId to cross icon, apparently this functionality dint work.
-----------------------App.js--------------------------------
import React, { useState } from "react";
import './App.css';
import Input from './Components/Input';
import Navbar from './Components/Navbar';
import Notesview from './Components/Notesview';
import Notesdata from "./Data/Notesdata";
function App() {
const [data, setData] = useState(Notesdata);
// const [pin, setpin] = useState(true)
const [iconId, seticonId] = useState([])
function handleDelete(id) {
let newData = data.filter((item) => item.id !== id)
setData(newData)
console.log(newData)
console.log(Notesdata)
console.log(0)
}
function handlePost(value) {
// Notesdata.push(value)
// setData(Notesdata)
// // console.log(typeof data)
// console.log(Notesdata)
setData([...data, value]);
}
function onPin(id) {
let index = data.map((item) => {
return item.id
}).indexOf(id)
let arr1 = data.slice(0, index).concat(data.slice(index + 1))
arr1.unshift(data[index])
setData(arr1);
seticonId([...iconId] , id)
console.log(iconId)
}
function handleclose() {
// setpin(!pin)
// seticonId("")
}
return (
<div className="App">
<header className="App-header">
<Navbar />
<Input data={data} handlePost={(value) => handlePost(value)} />
<Notesview handleDelete={handleDelete} Data={data} onPin={onPin} iconId={iconId} handleclose={handleclose} />
</header>
</div>
);
}
export default App;
----------------Noteview function(mapping function)---------------
import React from 'react'
import Notescard from './Notescard'
import "../Styles/Notes.css"
// import { useState } from 'react'
const Notesview = ({ Data, handleDelete, onPin , iconId, handleclose}) => {
return (
<>
<div className='notes'>
{Data && Data.map((item) => {
return <Notescard item={item} handleDelete={handleDelete} onPin={onPin} iconId={iconId} key={item.id} handleclose={handleclose}/>
})
}
</div>
</>
)
}
export default Notesview
-----------------------------Notescard component------------------
import React from "react";
import "../Styles/Notescard.css";
import { FaThumbtack, FaTrashAlt, FaPencilAlt ,FaTimesCircle} from "react-icons/fa";
// import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
const Notescard = ({ item , handleDelete,onPin,iconId,handleclose, key}) => {
return (
<>
<div className="box">
<div className="content">
<h2 className="item1">{item.title}</h2>
<h4 className="item1"> {item.tagline}</h4>
<p className="item2">{item.description}</p>
</div>
<div className="icons">
{iconId.includes(item.id) ? <FaTimesCircle onClick={handleclose}/> : <FaThumbtack id={item.id} onClick={() => onPin(item.id)}/> }
<FaTrashAlt onClick={() => handleDelete(item.id)}/>
<FaPencilAlt />
</div>
</div>
</>
);
};
export default Notescard;
Issue
You are passing two arguments to the seticonId state updater function.
seticonId([...iconId], id)
The id is never added to the iconId state.
Solution
Use a functional state update to append the id to the array.
seticonId((iconId) => iconId.concat(id));
Code:
const Notescard = ({ item, handleDelete, onPin, iconId, handleclose }) => {
return (
<div className="box">
<div className="content">
<h2 className="item1">{item.title}</h2>
<h4 className="item1"> {item.tagline}</h4>
<p className="item2">{item.description}</p>
</div>
<div className="icons">
{iconId.includes(item.id) ? (
<FaTimesCircle onClick={() => handleclose(item.id)} />
) : (
<FaThumbtack id={item.id} onClick={() => onPin(item.id)} />
)}
<FaTrashAlt onClick={() => handleDelete(item.id)} />
<FaPencilAlt />
</div>
</div>
);
};
...
const Notesview = ({ Data, handleDelete, onPin, iconId, handleclose }) => {
return (
<div className="notes">
{Data.map((item) => {
return (
<Notescard
item={item}
handleDelete={handleDelete}
onPin={onPin}
iconId={iconId}
key={item.id}
handleclose={handleclose}
/>
);
})}
</div>
);
};
...
export default function App() {
const [data, setData] = useState(Notesdata);
const [iconId, seticonId] = useState([]);
function handleDelete(id) {
let newData = data.filter((item) => item.id !== id);
setData(newData);
console.log(newData);
console.log(Notesdata);
console.log(0);
}
function handlePost(value) {
setData([...data, value]);
}
function onPin(id) {
setData((data) => {
const index = data.findIndex((item) => item.id === id);
const arr1 = data.slice(0, index).concat(data.slice(index + 1));
arr1.unshift(data[index]);
return arr1;
});
seticonId((iconId) => iconId.concat(id));
}
function handleclose(id) {
setData((data) => {
const index = data.findIndex((item) => item.id === id);
const insertIndex = data.findIndex((item) => !iconId.includes(item.id));
const arr1 = data.slice(0, index).concat(data.slice(index + 1));
arr1.splice(insertIndex - 1, 0, data[index]);
return arr1;
});
seticonId((iconId) => iconId.filter((elId) => elId !== id));
}
return (
<div className="App">
<Input data={data} handlePost={(value) => handlePost(value)} />
<Notesview
handleDelete={handleDelete}
Data={data}
onPin={onPin}
iconId={iconId}
handleclose={handleclose}
/>
</div>
);
}
import {useState, useEffect } from 'react'
import axios from 'axios'
const Countries = ({searchedCountries}) => {
console.log(searchedCountries.map(c => c.languages))
if (searchedCountries.length >= 10) {
return (
<div>
<p>too many countries to list, please narrow your search</p>
</div>
)
}
if (searchedCountries.length === 1) {
return (
<div>
capital: {searchedCountries.map(c => <p>{c.capital}</p>)}
area: {searchedCountries.map(c => <p>{c.area}</p>)}
<h2>Languages</h2>
<ul>
{searchedCountries.map(c => <li>{Object.values(c.languages)}</li>)}
</ul>
{searchedCountries.map(c => <img src={Object.values(c.flags)[0]} /> )}
</div>
)
}
return (
<ul>
{searchedCountries.map(c => <li>{c.name.common}</li>)}
</ul>
)
}
const App = () => {
const [countries, setCountries] = useState([])
const [newSearch, setNewSearch] = useState('')
const handleSearchChange = (event) => {
setNewSearch(event.target.value)
}
const searchedCountries =
countries.filter(c => c.name.common.includes(newSearch))
useEffect(() => {
console.log('effect')
axios
.get('https://restcountries.com/v3.1/all')
.then(response => {
console.log('promise fulfilled')
setCountries(response.data)
})
}, [])
return (
<div>
<div><p>find countries</p><input value={newSearch} onChange={handleSearchChange} /></div>
<div>
<h2>countries</h2>
<Countries searchedCountries={searchedCountries} />
</div>
</div>
)
}
export default App;
I am trying to list the languages of each country in my app, however, the languages render like this:
-EnglishSwedishItalian
instead of like this:
English
Swedish
Italian
Does anyone know how to render each of the Object.values(c.lanaguages) on its own line instead of all bunched together on one line?
Thanks.
You're passing an array (Obect.values(c.languages)) in a single <li> which gets flattened to a string by React.
<ul>
{searchedCountries.map(c => <li>{Object.values(c.languages)}</li>)}
</ul>
You'll need to instead map() the values array.
<ul>
{
searchedCountries.map(c =>
<li>
<ul>
{Object.values(c.languages).map(l => <li>{l}</li>)}
</ul>
</li>
)
}
</ul>
I'm doing project on React.js. I'm mapping the array and the error saying that the array is undefine even if it exists
<ul>
{details.extendedIngredients.map(ingredient => (
<li id={ingredient.id}>{ingredient.original}</li>
))}
</ul>
Full code:
import { useEffect, useState } from "react";
import styled from "styled-components";
import { useParams } from "react-router-dom";
function Recipe() {
let params = useParams();
const [details, setDetails] = useState({});
const [activeTab, setActiveTab] = useState("instructions");
const fetchDetails = async () => {
const data = await fetch(
`https://api.spoonacular.com/recipes/${params.name}/information?apiKey=${process.env.REACT_APP_API_KEY}`
);
const detailData = await data.json();
setDetails(detailData);
};
useEffect(() => {
fetchDetails();
}, [params.name]);
console.log(details.extendedIngredients);
return (
<DetailWrapper>
<div>
<h2>{details.title}</h2>
<img src={details.image} alt="" />
</div>
<Info>
<Button
className={activeTab === "instructions" ? "active" : ""}
onClick={() => setActiveTab("instructions")}
>
Instructions
</Button>
<Button
className={activeTab === "ingredients" ? "active" : ""}
onClick={() => setActiveTab("ingredients")}
>
Ingredients
</Button>
<div>
<h3 dangerouslySetInnerHTML={{ __html: details.summary }}></h3>
<h3 dangerouslySetInnerHTML={{ __html: details.instructions }}></h3>
</div>
<ul>
{details.extendedIngredients.map(ingredient => (
<li id={ingredient.id}>{ingredient.original}</li>
))}
</ul>
</Info>
</DetailWrapper>
)}
export default Recipe;
As setDetails supposed to save the details received from your API in an array, I guess that it must be initialised as an empty array
const [details, setDetails] = useState({});
As it will be an empty array, there will be no render when the component will be mounted from react.
Should be:
const [details, setDetails] = useState({});
edit this three parts:
first Part:
useEffect(() => {
fetchDetails().then(res=>
{setDetails(res.data); console.log(res)}
);
}, []);
second Part:
<ul>
{details?.extendedIngredients?.map(ingredient => (
<li id={ingredient.id}>{ingredient.original}</li>
))}
</ul>
third Part:
const fetchDetails = async (params) => {
const data = await fetch(
`https://api.spoonacular.com/recipes/${params.name}/information?
apiKey=${process.env.REACT_APP_API_KEY}`
return data;
);
All data comes into console but does not show into app
import React from 'react'
const Question_Answer_model = (props) => {
console.log(props.data)
const newvar = props.data.map((item) => {
return (
<li>{item.question_text}</li>
)
})
return (
<div>
<div>
<h2>Question And Answers...</h2>
{newvar}
</div>
</div>
)
}
export default Question_Answer_model
this is my consoledata which shows in console
here all comes into array in console
I think this will help you
import React from 'react'
const Question_Answer_model = (props) => {
//console.log(props)
const newvar = props.data.map((item) => {
return (
<li>{item.data.question_text}</li>
)
})
return (
<div>
<div>
<h2></h2>
{newvar}
</div>
</div>
)
}
export default Question_Answer_model
const newvar = props.data.map((item) => {
return (
<li>{item.question_text}</li>
)
})
This should be wrapped inside useCallback/useMemo/memberFunction.
It is not displaying because it is rendering for the first time and rendering when you get data.
Solved E.g
const { data } = props;
const newvar = useCallback(() => {
data.map((item) => {
return (
<li>{item.question_text}</li>
)
})
}, [data ])
use newvar inside return
Datalist is an array I'm trying to concat the boards array with the Datalist array, but when I console it doesn't reflect. On the other hand when I assign Datalist.concat(boards) to a variable it reflects example
const newArr = Datalist.concat(boards);
console.log(newArr)
(main code) please help me review it. Thanks in advance
import React, { useState, useEffect } from 'react';
import Modal from './Modal';
import { Datalist } from '../Data/Boards';
function Boards() {
const [boards, setboards] = useState(JSON.parse(localStorage.getItem('boards')) || []);
const [title, settitle] = useState('');
localStorage.setItem('boards', JSON.stringify(boards));
Datalist.concat(boards);
console.log(Datalist);
const handleChange = (e) => {
settitle(e.target.value);
};
const handleSubmit = () => {
if (title.length === 0) {
return;
}
setboards((prev) => [...prev, title]);
};
return (
<div>
<ul id="boards">
<BoardList boards={boards} />
</ul>
<Modal title={title} handleChange={handleChange} handleSubmit={handleSubmit} />
</div>
);
}
function BoardList({ boards }) {
const history = useHistory();
return (
<>
{boards.map((board, index) => (
<li
key={index}
onClick={() => {
history.push('./workspace');
}}
>
<h3>{board}</h3>
</li>
))}
</>
);
}
export default Boards;
That is the expected behaviour. The concat function does not alter the original arrays. You can read about it in the MDN docs
For your case you should be able to do Datalist = Datalist.concat(boards); and it should work like you're expecting