React - dynamic index of array. Giving undefined for object key - reactjs

I have a component that is collecting an array of objects from .json
function DisplaySingleQuestion() {
const [ displaySingleQuestion, setDisplaySingleQuestion ] = useState([]);
const [ questionNumber, setQuestionNumber ] = useState(0);
const [currentQuestion, setCurrentQuestion ] = useState("");
useEffect(() => {
fetch("./database/questions.json").then(
async resp => await resp.json()
).then(
data => setDisplaySingleQuestion(data.questions)
)
.catch(
err => console.log(err)
)
}, []);
useEffect(() => {
setCurrentQuestion(displaySingleQuestion[questionNumber])
}, [displaySingleQuestion]);
console.log(currentQuestion.question);
return (
<div>
<p>to jest Single Question</p>
<div style={{backgroundColor: "red"}}>
{/* <p>{displaySingleQuestion[questionNumber].question}</p> */}
</div>
</div>
)
}
If I ask for a specific array index it works well.
For example: displaySingleQuestion[0].question shows the right string.
If instead I get the 0 from the state, it gives undefined.
The component above gives undefined on console.log(currentQuestion.question);
However if I run console.log(currentQuestion); it shows the object in question:
{id: 1, question: "Question text?"}
id: 1question: "Question text?"
[[Prototype]]: Object
The JSON looks like this:
{
"questions": [
{
"id": 1,
"question": "Question text?"
},
{
"id": 2,
"question": "Banan??"
},
{
"id": 3,
"question": "Cytryna?"
},
{
"id": 4,
"question": "Dynia?"
},
{
"id": 5,
"question": "Eukaliptus?"
}
]
}
Why can't I select the question key by calling displaySingleQuestion[questionNumber].question?
What am I doing wrong, and how to fix it?
Thank you

Related

Having problems parsing json complex data in react js. Map error

App.js
I am facing this issue file error - Uncaught TypeError: items.data.map is not a function. I have tried some other options but did not work. I cant seem to find what I am doing wrong.
.then((res) => res.json())
.then((json) => {
this.setState({
items: json,
DataisLoaded: true
});
})
}
render() {
const { DataisLoaded, items } = this.state;
if (!DataisLoaded) return <div>
<h1> Loading data ... </h1> </div> ;
return (
<div className = "App">
<h1> Fetch data from an api in react </h1> {
items.data.map((item) => (
<ol key = { item.data} >
Continents: {item.data[0]}
</ol>
))
}
</div>
);
}
}
export default App;
JSON Data
Nested API data from json data type.
{
"data": {
"data": [
{
"project_id": "xxxx",
"title": "xxx34",
"description": "xxx23",
"expense": 1699126,
"budget": 6418516,
"country": "xxx",
"sector": [
{
"name": "Accelerate structural transformations",
"code": "18"
}
],
"sdg": [
{
"name": "Peace, justice, and strong institutions",
"id": "16"
}
],
"signature_solution": [
{
"name": "Strengthen effective, inclusive and accountable governance",
"id": "2"
}
],
"donor": [
"Australian DFAT",
"GLOBAL FUND TO FIGHT AIDS, TUBERCULOSIS",
"UNITED NATIONS DEVELOPMENT PRO"
],
"marker": [
"Hows",
"Joint Programme",
"Partner",
"Whos",
"COVID-19 Response"
]
},
{
],
"links": {
"next": null,
"previous": null
},
"count": 44
},
"status": 200,
"success": true
}
I tried data.data.map but still facing the same error. What am I doing wrong here?
Firstly, the TypeError you got is syntax error. The implementation of an arrow function must follow by curly brackets
items.data.map((item) => (
<ol key = { item.data} >
Continents: {item.data[0]}
</ol>
))
to
items.data.map((item) => {
<ol key = { item.data} >
Continents: {item.data[0]}
</ol>
})
Secondly, items you are mapping is a nest of JSON object - key: value pair. It's not suitable for mapping.
The mapping iterator or iterating an array is perfect when used to retrieve
data from a sequence item have the same or similar structure.
E.g:
const arr = [{"id": "1", "name": "a"}, {"id": "2", "name": "b"}, {"id": "3", "name": "c"}];
arr.map((item) => {
console.log(item.id);
console.log(item.name);
})
You should pretreat your data first.

.map is not a function with MaterialUI Tab component

So I'm trying to populate a in-memory MirageJS' database with a post request of the data in useEffect, making a get request after. Then I save the result to columnsNames state and use it to map this array and read the information as a label of Tab MaterialUI component. However, I have some questions:
When I put a console.log after useEffect or inside get request, both response.data and columnsNames state have 2 identical arrays. Why 2 and not 1?
At runtime the console prints
Uncaught TypeError: columnsNames.map is not a function
The above error occurred in the <ScrollableTabsButtonAuto> component
and nothing is showed in the screen. Why?
Anyone that could help me, thanks in advance!
Data.ts
export const data = [
{
"id": 1,
"title": "Test 1",
"steps": [
"Read a starting book",
"Keep calm and drink coffee",
"Don't Panic so much",
]
},
{
"id": 2,
"title": "Test 2",
"steps": [
"Get some helpful help",
"Don't loose yourself",
]
},
{
"id": 3,
"title": "Test 3",
"steps": [
]
},
{
"id": 4,
"title": "Test 4",
"steps": [
]
},
{
"id": 5,
"title": "Test 5",
"steps": [
]
},
{
"id": 6,
"title": "Test 6",
"steps": [
]
}
]
App.tsx
import { createServer, Model } from 'miragejs';
createServer({
models: {
columns: Model,
},
routes() {
this.namespace = 'api'
this.get('columns', () => {
return this.schema.all('columns')
})
this.post('columns', (schema, request) => {
const data = JSON.parse(request.requestBody)
return schema.create('columns', data)
})
}
})
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Tab.tsx
interface ColumnTypes {
id: number,
title: string,
steps: string[]
}
export default function ScrollableTabsButtonAuto() {
const [value, setValue] = React.useState(0);
const [columnsNames, setColumnsNames] = React.useState<ColumnTypes[]>([])
const handleChange = (event: React.SyntheticEvent, newValue: number) => {
setValue(newValue);
};
React.useEffect(() => {
api.post('columns', data)
.then( () => {
api.get<ColumnTypes[]>('columns')
.then(response => setColumnsNames(response.data))
})
}, [])
return (
<Box sx={{ maxWidth: { xs: 320, sm: 1280 }, bgcolor: 'background.paper' }}>
<Tabs
value={value}
onChange={handleChange}
variant="scrollable"
scrollButtons="auto"
aria-label="scrollable auto tabs example"
>
{columnsNames.map(({ id, title }) => (
<Tab
label={title}
key={id}
/>)
)}
</Tabs>
</Box>
);
}

making dynamic route by API with next+react

i'd like to make a dynamic route with react and next.js
I have an API like this.
[
{
"id": 1,
"name": "books",
"pages": "277",
"title": "Book A",
"no": 88
},
{
"id": 2,
"name": "books",
"pages": "90",
"title": "Book B",
"no": 32
},
{
"id": 4,
"name": "books",
"pages": "184",
"title": "Book C",
"no": 89
}
...
]
and this API will show in the screen like this. this is mapped li in Book.jsx
<li>
<p>{book.name}</p>
<p>{book.pages}</p>
</li>
Now, what i want to make is when i click li, it connects to the "no" of API and make a new window.
so I created [bookNo].jsx and the same location with pages > index.jsx and added these to [bookNo].jsx
const DetailedView = () => {
const router = useRouter();
const {bookNo} = router.query;
return (
<div>
<p>{bookId}</p>
</div>
);
};
to make router works, i added these code to Book.jsx
useEffect(() => {
getBooks().then(res => {
const book = res.data.DATA.RESPONSE.BOOKS;
for (let i = 0; i < book.length; i++) {
const bookNo = bookData[i].no;
}
}).catch(e => {
console.log(e)
})
}, [])
<Link href="pages/bookView/[bookId]" as={`/bookView/${bookId}`}>
<li onClick>
<p>{book.name}</p>
<p>{book.pages}</p>
</li>
</Link>
And I've got 2 errors that
ReferenceError: bookNo is not defined and router is not working at all.
Can anyone help me with this problem?

ReactHook adding array of an array state without duplicating the key

I am trying to add data grouping by the unit name for showing functionality
const [allData , setAllData]= useState([{'unit':'' , data:[]}])
useEffect(async () => {
await axios.get(`${BACKEND_URL}/data`).then(res => {
res.data.map(elem => {
setAllData(prev =>[...prev , { 'unit': elem.unitName, 'data': [elem.lessonName] }]);
});
});
}, []);
the result is duplicating the key for the subarray which is "unit" for my exampl:
[
{
"unit": "unit 1",
"data": [
"LO1"
]
},
{
"unit": "unit 2",
"data": [
"LO2"
]
},
{
"unit": "unit 3",
"data": [
"LO3"
]
},
{
"unit": "unit 1",
"data": [
"LO15"
]
}
]
Try like that, if find unique property unit rewrite data or push new element to array
useEffect(async () => {
await axios.get(`${BACKEND_URL}/data`).then(res => {
setAllData((prev) => {
let result = [...prev];
res.data.forEach(({ unitName: unit, lessonName }) => {
const index = result.findIndex((elem) => elem.unit === unit);
if (index >= 0) {
result[index].data = [...result[index].data, lessonName]
} else {
result.push({unit, data: [lessonName]});
}
});
return result;
});
});
}, []);

How to map a nested JSON response in React

I have to map the nested JSON result in React. The below one is the response I got as response from backend API.
{
"id": 2,
"name": "sanjna",
"email": "vv#gmail.com",
"address": "iiiii, hhh",
"gender": "1",
"tagline": "Friendly to all",
"description": "4 years experience in programming",
"languages": "English ",
"key_skills": [
{
"id": 1,
"name": "RUBY ON RAILS, HTML, BOOTSTRAP, JQUERY, REACT",
"relevant_experience": "4"
},
{
"id": 2,
"name": "ruby",
"relevant_experience": "2"
}
],
"certifications": [
{
"id": 1,
"name": "MCA",
"institution_name": "vvv unversity",
"certification_date": "20-12-2020",
"image": null
},
{
"id": 2,
"name": "HTML training",
"institution_name": "nnn unversity",
"certification_date": "20-12-2022",
"image": null
}
],
"educations": [
{
"id": 1,
"qualification": "MCA",
"course": "Masters Degree PG",
"institute": "kkk",
"ins_location": "jjjj",
"passing_year": "2015"
}
]
}
This is my React code to get this response
const [singleUserDetail, setsingleUserDetail] = React.useState('');
let logged_user_id = job_seeker.actable_id;
const getsingleUserDetails = (logged_user_id) => {
axios
.get(`http://localhost:3001/users/${logged_user_id}`, { withCredentials: true })
.then((response) => {
const singleUserDetail = response.data;
setsingleUserDetail(response.data)
console.log(response.data); //prints the above JSON results in console
})
.catch((error) => {
console.log(" error", error);
});
};
React.useEffect(() => {
getsingleUserDetails(logged_user_id);
}, [logged_user_id]);
When I prints {singleUserDetail.name} it gives me result sanjna
{singleUserDetail.email} it gives me result vvv#gmail.com
{singleUserDetail. address} it gives me result iiiii, hhh. from my above JSON result
But how to print keyskills, certifications and educations here with mapping. I'm a beginner in React.
Youu can do something like this, my example is very simple,but you can complicate this as much as you need, with conditions or loops in loops.
<div>
{singleUserDetail.name},{singleUserDetail.email},{singleUserDetail.address},{singleUserDetail.gender},{singleUserDetail.tagline},{singleUserDetail.description}, {singleUserDetail.languages}
</div>
{singleUserDetail.key_skills.map((skill)=>{
return(
<div key={skill.id}>
{skill.name}:{skill.relevant_experience}
</div>
);
})}
{singleUserDetail.certifications.map((certification)=>{
return(
<div key={certification.id}>
{certification.name},{certification.institution_name},{certification.certification_date}
</div>
);
})}
{singleUserDetail.educations.map((education)=>{
return(
<div key={education.id}>
{education.qualification},{education.course},{education.institute}
</div>
);
})}
For more information, React documentation

Resources