show api data to frontend(poll) using reactjs - javascript

I want to fetch data from API and show frontend using react but I am getting error from frontend side which is (TypeError: answers.map is not a function ) so how can I solve this error --
MY CODE IS -
import React, { useState, useEffect } from "react";
import Poll from "react-polls";
import { getPolls } from "../helper/coreapicalls";
const MainPoll = () => {
const [polls, setPoll] = useState([]);
const [error, seterror] = useState(false);
// Setting answers to state to reload the component with each vote
const [pollAnswers, setPollAnswers] = useState([]);
useEffect(() => {
loadPoll();
}, []);
const loadPoll = () => {
getPolls().then((data) => {
if (data.error) {
seterror(data.error);
} else {
setPoll(data);
console.log(data);
}
});
};
// Handling user vote
// Increments the votes count of answer when the user votes
return (
<div className="">
<div className="container">
<h1 className="blog_heading">Poll's of the Day</h1>
<div className="row">
{polls.reverse().map((poll, index) => (
<div className="col-lg-4 col-12" key={index}>
<Poll question={poll.question} answers={poll.options} />
</div>
))}
</div>
</div>
</div>
);
};
export default MainPoll;
Data which I am getting from API is-
enter image description here
Here I have Question , 3 options how can I show to frontend
Error -enter image description here

The problem is:
field options from the API is an object as I see.
But Poll component trying to interact with it like it is an Array: answers.map(answer => answer.option)
As I see from the doc, data format should be:
[
{ option: 'Yes', votes: 8 },
{ option: 'No', votes: 2 }
]
UPDATE: you can use a similar snippet to transform your data into the required format.
data.map(answer => {
return {
question: answer.question,
answers: Object.keys(answer.options).map(key => {return {option: key, votes: 0}})
}
})

Related

My React App state is not in sync with my Firebase

I am having a hard time getting my React App working properly.
The thing is that I tried to use UseEffect hooks only to run side effects in my app and this has brought me some problems.
In this simple component I have a chat that get data from Firebase and is capable of updating the Db. I have no problem with the Firebase side but on the front end, the first render is not able to get me the messages into state properly.
I feel that it has of course something to do with async behaviors.
I will try to explain you the flow of my component :
The message text is kept in a const in state call "inputText"; when the form is submited a const call "numberOfMessageSent" is incremented; I have a UseEffect Hook that has [numberOfMessageSent] in its depedency; so after the first mount of the component and when "NumberOfMessageSent" increments the callback will fire; this callback fires 2 async functions: one to fetch the current discussion from the db and another to create a discussion object or update an existing one into the Db. I have a condition :
"numberOfMessagesSent !== 0 && asyncWarperCreateDiscussionInDb()" in the UseEffect Hook so a new discussion empty discussion won't be created the first this component mount.
My problem is that no discussion is displayed (nor properly fetched and stored into state) BEFORE I send a first message. After I send this first message everything works properly.
Can someone help me to understand this better ?
Thank you very much
here is my code :
import React, { useContext, useEffect, useState } from "react";
import "./card-medium-message.style.scss";
import likeEmpty from "./like-empty.png";
import likeFull from "./like-full.png";
import cancel from "./cancel.png";
import send from "./send.png";
import back from "./back.png";
import { useNavigate, useParams } from "react-router-dom";
import { UsersListContext } from "../../context/usersList-context/users-list-context";
import { UserContext } from "../../context/user-context/user-context";
import {
createDiscussionInDb,
goFetchDiscussionInDb,
goFetchDisscussion,
} from "../../utils/firebase";
const CardMediumMessage = () => {
const params = useParams();
const { usersListCTX } = useContext(UsersListContext);
const { currentUserContext } = useContext(UserContext);
const currentUserClickedOn = usersListCTX.filter(
(user) => user.displayName === params.name
);
console.log(currentUserContext);
console.log(currentUserClickedOn[0]);
const [messages, setMessages] = useState([]);
const [inputText, setInputText] = useState("");
const [numberOfMessagesSent, setNumberOfMessagesSent] = useState(0);
const asyncWarperFetchDiscussionInDb = async () => {
if (currentUserClickedOn[0]) {
const discussion = await goFetchDiscussionInDb(
currentUserContext.displayName,
currentUserClickedOn[0].displayName
);
setMessages(discussion.messages);
}
};
const asyncWarperCreateDiscussionInDb = async () => {
await createDiscussionInDb(
currentUserContext.displayName,
currentUserClickedOn[0].displayName,
inputText
);
resetField();
};
useEffect(() => {
numberOfMessagesSent !== 0 && asyncWarperCreateDiscussionInDb();
asyncWarperFetchDiscussionInDb();
console.log(
"this is written after first render of the component or numberOfMessagesSent was updated"
);
}, [numberOfMessagesSent]);
const messageSubmit = async (e) => {
e.preventDefault();
if (inputText == "") {
return;
}
setNumberOfMessagesSent(numberOfMessagesSent + 1);
};
const textChanged = (e) => {
setInputText(e.target.value);
};
const resetField = () => {
setInputText("");
};
const navigate = useNavigate();
messages && console.log(messages);
return (
<div className="card-medium-warp">
<div className="card-medium-message">
<div className="section1" onClick={() => navigate(-1)}>
<div className="profile-image-outer-circle">
{currentUserClickedOn[0] ? (
<img
src={`https://api.dicebear.com/5.x/micah/svg?seed=${currentUserClickedOn[0].displayName}`}
alt="avatar"
className="profile-image"
/>
) : undefined}
</div>
{currentUserClickedOn[0] ? (
<h2 className="name">{currentUserClickedOn[0].displayName} </h2>
) : undefined}
<div
className="back"
style={{ backgroundImage: `url(${back})` }}
></div>
</div>
<div className="section2">
{messages
? messages.map((messageObject, index) => (
<p
key={index}
className={
messageObject.by === currentUserContext.displayName
? "sender-message"
: "receiver-message"
}
>
{messageObject.message}
</p>
))
: undefined}
</div>
<form className="section3" onSubmit={messageSubmit}>
<input
type="text"
className="input"
placeholder="your message"
onChange={textChanged}
value={inputText}
autoFocus
/>
<div
className="send-message"
style={{ backgroundImage: `url(${send})` }}
></div>
</form>
</div>
</div>
);
};
export default CardMediumMessage;
I think I found the solution so I would like to share it :
My mistake was that I was calling functions that were async in themselves but I didn't chain them in an async/await manner.
This is what I am talking about :
const asyncWarperSequence = async () => {
numberOfMessagesSent !== 0 && (await asyncWarperCreateDiscussionInDb());
await asyncWarperFetchDiscussionInDb();
};
useEffect(() => {
console.log("UseEffect Fired");
asyncWarperSequence();
}, [numberOfMessagesSent]);

Manipulating Local Data in React JS, Can Not Get It To Work For My Quiz Application

I'm new to coding (it's been around three months) and I have a problem with React JS.
I took freecodecamp's eleven hour REact JS Course on YouTube and in the end of the video, there is a quiz application challenge called quizzy.
You can go to my github project file and check it out
I came to a point where I can't get the answer options selected.
I want to toggle between a different colored background whenever I click on an answer button, and I wanted it to stay as long as that button is clicked. As far as I checked, there seems to be a problem with the App.js file where I try to manipulate the data's isSelected key inside toggle function. I kindly ask anyone for help. I just don't know what I am doing wrong and it's driving me crazy.
My App.js file looks like this:
import { nanoid } from 'nanoid';
import React from 'react';
import data from '../data';
import QuestionsAndAnswers from './QuestionsAndAnswers';
function Quiz() {
const [quiz, setQuiz] = React.useState(data);
// const [isSelected, setIsSelected] = React.useState(false);
React.useEffect(() => {
const newData = data.map((data) => ({
...data,
answerOptions: data.answerOptions.map(answerOptions => ({
...answerOptions,
optionsID: nanoid()
}))
}))
setQuiz(newData);
}, [])
const handleSubmit = (event) => {
event.preventDefault();
console.log("completed")
}
function toggle(id, value) {
console.log(id, value)
setQuiz((oldState) => oldState.map((data) => {
return data.id === id
? {
...data,
answerOptions: data.answerOptions.map(answerOptions => {
return answerOptions.answerText === value
? {
...answerOptions,
isSelected: !answerOptions.isSelected
}
: {
...answerOptions,
isSelected: false
}
})
}
: data
}))
}
const selectedOptions = data.map(data => {
return (data.answerOptions.isSelected ? data : null)
})
console.log(selectedOptions)
const questions = quiz.map((quiz, index) => {
return (
<QuestionsAndAnswers
key={index}
quiz={quiz}
setQuiz={setQuiz}
toggle={toggle}
/>
)
})
// main function
return (
<main>
<form className="form-container" onSubmit={handleSubmit}>
<h2 className='header'>QuizCript</h2>
{questions}
<button className="complete-quiz-button" type='submit'>Complete the Quiz</button>
</form>
</main>
)
}
export default Quiz;

How to pass JSON data using useNavigation Hooks in React Js?

This is my Json file which I created in my app.
export const Data = [
{
id: 1,
title: "Tilte 1",
description: "Decription 1 Data",
},
{
id: 2,
title: "Tilte 2",
description: "Decription 2 Data",
}
];
This is my main file from where I navigate it. I use json file to display all the records on page. When I click on selected item it will get its id and navigate to another page, where i can get the data of selected item coming from json.
import React from "react";
import { Data } from "./JSON"
import { useNavigate } from 'react-router-dom'
const Home = () => {
let naviagte = useNavigate();
return (
<>
{Data.map((data, key) => {
return (
<div class="card" >
<div class="card-body">
<h5 class="card-title" key={key.id}>{data.title}</h5>
<p class="card-text">{data.description}</p>
<button onClick={() => naviagte(`/service/${data.id}`)}>{data.title} </button>
</div>
</div>
);
})}
</>
)
}
export default Home;
When I navigate to another page where I want to display all data regarding the selected id. It shows only id not all data.
import React, {useState, useEffect} from "react";
import { Data } from "../home/JSON"
import { useParams } from "react-router-dom";
const Service = () => {
const { id } = useParams();
const [data, setData] =useState('');
console.log("check", data);
useEffect(() => {
setData (Data.map((_data) => _data.id === id ))
}, [id])
return(
<>
{id}
{data.title}
{data.description}
</>
)
}
export default Service;
Please guide me what I miss here. Thanks in Advance
Since you are importing the data in both places you just need to find the data by the id property instead of mapping it to booleans. Keep in mind that your id property is a number but the id route param will be a string, so you will need to convert them to a compatible type for the strict equality (===) check.
Example:
useEffect(() => {
setData(Data.find((_data) => String(_data.id) === id));
}, [id]);
Since data is treated as an object in the render return you'll want to insure you maintain a valid state invariant. Update the initial data state to be an object, and check that Array.prototype.find returned a defined object from the Data array before updating state.
const Service = () => {
const { id } = useParams();
const [data, setData] = useState({});
console.log("check", data);
useEffect(() => {
const data = Data.find((_data) => String(_data.id) === id);
if (data) {
setData(data);
}
}, [id]);
return (
<>
{id}
{data.title}
{data.description}
</>
);
};

Is there a way to re-render data after submit-axios post request? ReactJS

So I've recently started on learning React, where I've created a little project for me. Now on backend everythings works etc.
By now everything was going good, but now I've got stuck.
Now about the page: I've got page, where u can see details about single article, and get info about loan for price of article. I've made it on backend that default value of it is 60 months, and if u want different period, u submit other months value eg. 120. So on backend when I hit route http://localhost:8080/api/article/id i get response of data and loan is calculated with 60 months. Now if in body i send eg. {"months": 6} i get different data in response which is expected and working fine.
Now where I've hit a wall: on front end I have no idea how to update data when form is submited. Here you can see my from:
And idea is when u enter eg. 6 to lower part of page is changed:
These last two right clomuns should be changed.
Now I've tried to send with id months to the actions and then refresh page when disptach is triggered but no success - and I know that after refresh months are reseted to default value.
Now these values come from that localhost route and I'm fetching it with a axios call, and displaying content
Here is my Article.js component:
import React, { useEffect, useState, useRef } from 'react';
import { useDispatch } from 'react-redux';
import { Link } from 'react-router-dom';
import Form from 'react-validation/build/form';
import Input from 'react-validation/build/input';
import CheckButton from 'react-validation/build/button';
import ArticleService from '../services/article.service';
import { getArticle } from '../actions/articles';
const Article = (props) => {
const form = useRef();
const checkBtn = useRef();
const [content, setContent] = useState([]);
const [dataArr, setDataArr] = useState([]);
const [months, setMonths] = useState([]);
const [loading, setLoading] = useState(false);
const dispatch = useDispatch();
const onChangeMonths = (e) => {
const months = e.target.value;
setMonths(months);
};
const handleMonths = (e) => {
e.preventDefault();
setLoading(true);
if (checkBtn.current.context._errors.length === 0) {
const id = props.match.params.id;
dispatch(getArticle(id, months))
.then(() => {})
.catch(() => {
setLoading(false);
});
} else {
setLoading(false);
}
};
useEffect(() => {
const fetchPosts = async () => {
const id = props.match.params.id;
const res = await ArticleService.article(id);
setContent(res.data);
const data = res.data.kredit;
const dataArr = [];
dataArr.push({
name: 'kreditNKS-rataNKS',
price: data.kreditNKS.map((item) => {
return item;
}),
rate: data.rataNKS.map((item) => {
return item;
}),
nks: data.stopaNKS.map((item) => {
return item;
}),
banka: {
eks: data.stopaEKS.map((item) => {
return item;
}),
bankname: data.ime.map((item) => {
return item;
}),
type: data.tip.map((item) => {
return item;
}),
},
});
setDataArr(dataArr);
};
fetchPosts();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const a = dataArr;
return (
<div>
<p className='text-dark'>
<Link to='/dashboard'>
<i className='fas fa-arrow-left'></i> Nazad
</Link>
</p>
<div className='container p-3 my-3 bg-dark text-white'>
<strong>Artikal id:{content.id}</strong>
<br></br>
<br></br>
<div className='row'>
<div className='col-sm'>
Opis:
<br></br>
{content.descr}
</div>
<div className='col-sm'>
Cijena
<br></br>
{content.price}
</div>
<div className='col-sm'>
Cijena po metru kvadratnom:
<br></br>
{content.ppm2}/m2
</div>
</div>
</div>
<div className='container'>
<h3>KREDITI ZA CIJENU {content.price}</h3>
<Form onSubmit={handleMonths} ref={form}>
<div className='form-group'>
<label>Vrijeme otplate u mjesecima:</label>
<Input
type='text'
className='form-control w-25'
name='months'
value={months}
onChange={onChangeMonths}
/>
<button
className='btn btn-primary btn-block w-25'
disabled={loading}
>
{loading && (
<span className='spinner-border spinner-border-sm'></span>
)}
<span>Click</span>
</button>
<CheckButton style={{ display: 'none' }} ref={checkBtn} />
<small>
Ako se ne unese vrijeme otplate kredita, kredit se izračunava za
60 mjeseci
</small>
</div>
</Form>
</div>
<div className='container-fluid'>
<br></br>
<h4>Lista kredita</h4>
<div className='row'>
<div className='col-sm'>
<h4>Informacije o banci</h4>
{a &&
a.map((item) =>
item.banka.bankname.map((its, index) => (
<div className='card card-body flex-fill'>
<h2>{its}</h2>
<h6>EKS: {item.banka.eks[index]}%</h6>
<h6>Tip: {item.banka.type[index]} K.S</h6>
</div>
))
)}
</div>
<div className='col-sm'>
<h4>NKS</h4>
{a &&
a.map((item) =>
item.nks.map((s) => (
<div className='card card-body flex-fill'>
<h2>{s}</h2>
</div>
))
)}
</div>
<div className='col-sm'>
<h4>Ukupna cijena kredita</h4>
{a &&
a.map((item) =>
item.price.map((it2) => (
<div className='card card-body flex-fill'>
<h2>{it2} KM</h2>
</div>
))
)}
</div>
<div className='col-sm'>
<h4>Rata</h4>
{a &&
a.map((item) =>
item.rate.map((it2) => (
<div className='card card-body flex-fill'>
<h2>{it2} KM/mj</h2>
</div>
))
)}
</div>
</div>
</div>
</div>
);
};
export default Article;
actions/article.js
import { SET_MESSAGE, RATE_UPDATE, UPDATE_FAIL } from './types';
import ArticleService from '../services/article.service';
export const getArticle = (id, months) => (dispatch) => {
return ArticleService.article(id, months).then(
(response) => {
dispatch({
type: RATE_UPDATE,
});
dispatch({
type: SET_MESSAGE,
payload: response.data.message,
});
return Promise.resolve();
},
(error) => {
const message =
(error.response &&
error.response.data &&
error.response.data.message) ||
error.message ||
error.toString();
dispatch({
type: UPDATE_FAIL,
});
dispatch({
type: SET_MESSAGE,
payload: message,
});
return Promise.reject();
}
);
};
services/article.service.js
import axios from 'axios';
//const API_URL = 'https://stanbackapp.azurewebsites.net/api/articles/';
const API_URL = 'http://localhost:8080/api/articles/';
//const dAPI_URL = 'https://stanbackapp.azurewebsites.net/api/article/';
const dAPI_URL = 'http://localhost:8080/api/article/';
const articles = () => {
return axios.get(API_URL);
};
const article = (id, months) => {
return axios.post(dAPI_URL + `${id}`, {
months,
});
};
export default {
articles,
article,
};
I want to frontend behave just like backend: If i don't send anything in the form display data for 60 months.(that is what is doing now), but if i type in 10 and hit click a want to page re-render these two last columns(because if you send months only them are changed) and display that new data.
Also I've tried this in dispatch:
dispatch(getArticle(id, months))
.then((response) => console.log(response))
But console.log is undefiend
Any tips? Thanks!
I think your issue may be that you are mixing state. The first time you fetch data (via useEffect), you are fetching directly via axios. However, when you fetch data in the handleMonths, you are passing the action over to Redux, which operates very differently. The other issue is that the component never retrieves the data from Redux, so any updates are essentially ignored.
My suggestion would be to use the same method for retrieving data the first time as you do subsequent times:
const handleMonths = (e) => {
...
if (checkBtn.current.context._errors.length === 0) {
const id = props.match.params.id;
try {
const res = await ArticleService.article(id, months);
... // Handle the response appropriately.
setContent(res.data);
const data = res.data.kredit;
const dataArr = [];
dataArr.push({
name: 'kreditNKS-rataNKS',
price: data.kreditNKS,
rate: data.rataNKS,
nks: data.stopaNKS,
banka: {
eks: data.stopaEKS,
bankname: data.ime,
type: data.tip,
},
});
setDataArr(dataArr);
} catch (e) {
setLoading(false);
}
} else {
setLoading(false);
}
};
This provides 2 benefits:
You can extract the method for handling the response data to make it the same for both cases.
You remove the need for an external state handler (i.e. Redux) which you may not need.

don't understand how can I get pollId from reactjs poll

this is my react code here I am getting react poll using API but when I start working on handalchange For POST API request I need (PollId,userId and answer) I am getting userId through { const userId = isAutheticated() && isAutheticated().user._id; } but I do not understand how can I get PollId from my all polls, please help...!
import React, { useState, useEffect } from "react";
import Poll from "react-polls";
import "../../styles.css";
import { isAutheticated } from "../../auth/helper/index";
import { getPolls, postPoll } from "../helper/coreapicalls";
import { useParams } from "react-router-dom";
const MainPoll = () => {
const userId = isAutheticated() && isAutheticated().user._id;
const pollId = useParams();
const id = pollId._Id;
console.log(id);
const [polls, setPoll] = useState([]);
const [error, seterror] = useState(false);
// Setting answers to state to reload the component with each vote
const [pollAnswers, setPollAnswers] = useState([]);
useEffect(() => {
loadPoll();
}, []);
const loadPoll = () => {
getPolls().then((data) => {
if (data.error) {
seterror(data.error);
} else {
setPoll(data);
console.log(data);
}
});
};
// Handling user vote
// Increments the votes count of answer when the user votes
const handalchange = () => {
postPoll();
console.log("hello");
};
return (
<div className="">
<div className="container my-5">
<h1 className="blog_heading my-3">Poll's of the Day</h1>
<div className="row">
{polls.reverse().map((poll, index) => (
<div className="col-lg-4 col-12 poll_border" key={index}>
<Poll
noStorage
question={poll.question}
answers={Object.keys(poll.options).map((key) => {
return {
option: key,
votes: poll.options[key].length,
};
})}
onVote={handalchange}
className="mb-2"
/>
</div>
))}
</div>
</div>
</div>
);
};
export default MainPoll;
my frontend image -
Here I have 5 polls , so I can not get PollId from useParams ...! so how can I get..?
Your component seems to represent list of polls, not any specific poll. So if you have an array of polls instead of one poll, than you have multiple ids instead of the single one.
You can get them by mapping your polls array like that:
const pollIds = polls.map((poll) => poll.id); // or any other prop that stores id

Categories