I'm connecting my Node backend(connected the database using Microsoft SQL Server) to React front-end. Note: The backend works great and tested with postman for all endpoints.
While connecting to it, throws me this error : "Validation failed for parameter 'id'. Invalid number."
App.js
import React, { useState, useEffect } from "react";
import axios from "axios";
import './App.css';
import Header from "./components/Header";
import Search from "./components/Search";
import Events from "./components/Events";
const App = () => {
const [customers, setCustomers] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [searchQuery, setSearchQuery] = useState("");
useEffect(() => {
const fetchEvents = async () => {
const res = await axios(
`http://localhost:8080/api/event/${setSearchQuery}`
);
console.log(res.data);
setCustomers(res.data);
setIsLoading(false);
};
fetchEvents();
}, [searchQuery]);
return (
<div className="container">
<Header />
<Search getQuery={(sq) => setSearchQuery(sq)} />
<Events isLoading={isLoading} customers={customers} />
</div>
);
};
export default App;
Event.js
import React from "react";
const Event = ({ customer }) => {
return (
<div className="card">
<div className="card-inner">
<div className="card-front">
<img src={customer.img} alt="" />
</div>
<div className="card-back">
<h1>{customer.id}</h1>
<ul>
<li>
<strong>Customer ID:</strong> {customer.id}
</li>
<li>
<strong>Customer Number:</strong> {customer.Cus_no}
</li>
<li>
<strong>Range Name:</strong> {customer.RangeName}
</li>
<li>
<strong>Color:</strong> {customer.Color}
</li>
<li>
<strong>Blade Text:</strong> {customer.BladeTExt}
</li>
<li>
<strong>Special Notes:</strong> {customer.SpecialNotes}
</li>
<li>
<strong>Box Quantity:</strong> {customer.box_qty}
</li>
</ul>
</div>
</div>
</div>
);
};
export default Event;
Events.js
import React from "react";
import Event from "./Event";
import Spinner from "./Spinner.js";
const Events = ({ customers, isLoading }) => {
return isLoading ? (
<Spinner />
) : (
<section className="cards">
{customers.map((customer) => (
<Event key={customer.id} customer={customer}></Event> //key={customer.id}
))}
</section>
);
};
export default Events;
Search.js
import React, { useState } from "react";
const Search = ({ getQuery }) => {
const [number, setNumber] = useState(0);
const onChange = (sq) => {
setNumber(sq);
getQuery(sq);
};
return (
<section className="search">
<form>
<input
type="Number"
className="form-control"
placeholder="Search Customer Numbers"
value={number}
onChange={(e) => onChange(e.target.value)}
autoFocus
/>
</form>
</section>
);
};
export default Search;
For better understanding here is a Sample SQL Table output with the data types I created : https://dbfiddle.uk/?rdbms=sqlserver_2019&fiddle=c925fb80326b4c3ed2117beddb73b451
Now comes the great part, whenever I use the endpoint "http://localhost:8080/api/events" the whole customer data set displays correctly as it supposed to. But for the endpoint "http://localhost:8080/api/event/${setSearchQuery}" it gives me the error.
I think your problem is here:
const [searchQuery, setSearchQuery] = useState("");
your backend API for fetching event needs an id for it and when every your component mounts to the dom, your useEffect kicks in and calls the API! but meanwhile your state of searchQuery is an empty string!
NOTE:
const res = await axios(
`http://localhost:8080/api/event/${setSearchQuery}`
);
you are using setSearchQuery in your endpoint string instead of searchQuery!
that being said, I think still you will get an error even after changing that bug in your URL! because you still send an empty string as id for your backend API!
So the best solution would be to provide a default id for your searchQuery in your useState instead of passing an empty string, or if you cannot provide a default value, make sure that your api does not broke when you providing empty string to it!
Related
I have a problem with data displaying. Probably the JSX content is rendering too fast before data is actually fetched from API and that causing the following:
Uncaught TypeError: Cannot read properties of undefined (reading 'name')
I checked with console.log; sometimes it's fetching, sometimes not. Also, when I comment out this {concerts[1].name}, then data is loaded and populated. However, when I run it like in the example below, data is not populating, and I am getting errors.
import React from "react";
import { useEffect, useState } from "react";
import axios from "axios";
export const ConcertNewest = () => {
const [concerts, setConcerts] = useState([]);
useEffect(() => {
const loadConcerts = async () => {
const response = await axios.get("/data/concerts");
setConcerts(response.data);
};
loadConcerts();
}, []);
console.log("concerts: " + concerts.length);
return (
<show>
<h1>Newest concerts </h1>
<div>
<div className="card">
<img src="" style={{ width: 100 }} />
<div className="card-text">
<h4> {concerts[1].name}</h4>
</div>
</div>
</div>
</show>
);
};
The code inside useEffect runs after the JSX is rendered. That's by design. So you are ending up with concerts[1].name while concerts is still empty.
A common way to tackle this is to show some loading indicator while the data is being fetched, like so, for example:
import React from "react";
import { useEffect, useState } from "react";
import axios from "axios";
export const ConcertNewest = () => {
const [concerts, setConcerts] = useState([]);
useEffect(() => {
const loadConcerts = async () => {
const response = await axios.get("/data/concerts");
setConcerts(response.data);
};
loadConcerts();
}, []);
if (!concerts.length) {
return <p>Loading...</p>;
}
return (
<show>
<h1>Newest concerts </h1>
<div>
<div className="card">
<img src="" style={{ width: 100 }} />
<div className="card-text">
<h4> {concerts[1].name}</h4>
</div>
</div>
</div>
</show>
);
};
Hello I am making an application to practice React, my notes app has a pagination which works perfectly, the problem is in the search engine, which only looks for notes from the page I'm on, for example, if I'm on page 2 and I look for a note on page 2, it shows it, however if the note is on a different page, it doesn't show it, it doesn't find it.
I know where the problem is but I'm not sure how to solve it, I'm a bit new to React and I was asking for your help.
I was able to do my pagination with the package react-paginate here is the documentation https://www.npmjs.com/package/react-paginate
My code:
Component App.js
import { useState, useEffect } from "react";
import { nanoid } from 'nanoid';
import './App.css';
import Search from "./components/Search";
import Header from "./components/Header";
import Pagination from "./components/Pagination";
const App = () => {
const [notes, setNotes] = useState([]);
const [searchText, setSearchText] = useState('');
const [darkMode, setDarkMode] = useState(false);
const [showNote, setShowNote] = useState(true); //eslint-disable-line
useEffect(() => {
const saveNotes = JSON.parse(localStorage.getItem('notes-data'));
if (saveNotes){
setNotes(saveNotes);
}
}, []);
useEffect(() => {
localStorage.setItem('notes-data', JSON.stringify(notes))
},[notes])
const addNote = (inputText, text) => {
const date = new Date();
const newNote = {
id: nanoid(),
title: inputText,
text: text,
date: date.toLocaleString()
}
const newNotes = [newNote, ...notes];
setNotes(newNotes)
}
const deleteNote = (id) => {
var response = window.confirm("Are you sure?");
if (response){
const notesUpdated = notes.filter((note) => note.id !== id)
setNotes(notesUpdated);
}
}
return (
<div className={darkMode ? 'dark-mode' : ''}>
<div className="container">
<Header
handleToggleTheme={setDarkMode}
/>
<Search
handleSearchNote={setSearchText}
setShowNote={setShowNote}
/>
<Pagination
data={notes}
handleAddNote={addNote}
handleDeleteNote={deleteNote}
searchText={searchText}
/>
</div>
</div>
)
}
export default App;
Component Pagination.js
import React, { useEffect, useState } from 'react'
import ReactPaginate from 'react-paginate';
import '../styles/Pagination.css';
import NoteList from './NoteList';
import { MdSkipPrevious, MdSkipNext } from 'react-icons/md';
const Pagination = (props) => {
const { data, searchText, handleAddNote, handleDeleteNote } = props;
// We start with an empty list of items.
const [currentItems, setCurrentItems] = useState([]);
const [pageCount, setPageCount] = useState(0);
// Here we use item offsets; we could also use page offsets
// following the API or data you're working with.
const [itemOffset, setItemOffset] = useState(0);
const itemsPerPage = 9;
useEffect(() => {
// Fetch items from another resources.
const endOffset = itemOffset + itemsPerPage;
console.log(`Loading items from ${itemOffset} to ${endOffset}`);
setCurrentItems(data.slice(itemOffset, endOffset));
setPageCount(Math.ceil(data.length / itemsPerPage));
}, [itemOffset, itemsPerPage, data]);
// Invoke when user click to request another page.
const handlePageClick = (event) => {
const newOffset = (event.selected * itemsPerPage) % data.length;
console.log(
`User requested page number ${event.selected}, which is offset ${newOffset}`
);
setItemOffset(newOffset);
};
return (
<>
<NoteList
notes={currentItems.filter((noteText) =>
noteText.title.toLowerCase().includes(searchText)
)}
handleAddNote={handleAddNote}
handleDeleteNote={handleDeleteNote}
/>
<div className="pagination-wrapper">
<ReactPaginate
breakLabel="..."
nextLabel={<MdSkipNext
className='icons'
/>}
onPageChange={handlePageClick}
pageRangeDisplayed={3}
pageCount={pageCount}
previousLabel={<MdSkipPrevious
className='icons'
/>}
renderOnZeroPageCount={null}
containerClassName="pagination"
pageLinkClassName="page-num"
previousLinkClassName="page-num"
nextLinkClassName="page-num"
activeLinkClassName="activee boxx"
/>
</div>
</>
);
}
export default Pagination;
Component NoteList.js
import React from 'react'
import Note from './Note'
import '../styles/NoteList.css'
import AddNote from './AddNote'
const NoteList = ({ notes, handleAddNote, handleDeleteNote }) => {
return (
<>
<div className="add-notes-wrapper">
<AddNote
handleAddNote={handleAddNote}
/>
</div>
<div className='notes-list'>
{notes.map((note =>
<Note
key={note.id}
id={note.id}
title={note.title}
text={note.text}
date={note.date}
handleDeleteNote={handleDeleteNote}
/>
))}
</div>
</>
)
}
export default NoteList;
Component Search.js
//import React, { useState } from 'react'
import {MdSearch, MdAdd} from 'react-icons/md'
import '../styles/Search.css'
const Search = ({ handleSearchNote, setShowNote }) => {
const handleShowAddNote = () => {
if (setShowNote){
let addNote = document.querySelector('.new');
addNote.classList.add('wobble-horizontal-top')
addNote.style.display='flex';
document.querySelector('.notes-list').style.display='none';
document.querySelector('.pagination').style.display='none';
}
}
return (
<div className='search'>
<div className="input-wrapper">
<MdSearch
className='icon search-icon'
/>
<input
type="text"
placeholder='What note are you looking for?'
onChange={(event) => handleSearchNote(event.target.value) }
/>
</div>
<div className="btn-wrapper-search">
<button
className='btn-addNote'
onClick={handleShowAddNote}>
Nueva Nota
</button>
<MdAdd
className='icon add-icon'
/>
</div>
</div>
)
}
export default Search
The problem is in the component Pagination.js because I'm filtering the notes on each page with the currentItems variable, if I did it with the data variable it would work, but then it would show all the notes, and I don't want that, I currently want to show 9 notes per page.
greetings and thanks in advance.
Edit:
#Newbie I'm doing what you said, but I don't know if you mean this, in my Pagination.js component I did:
useEffect(() => {
const filterNotes=data.filter((noteText) =>
noteText.title.toLowerCase().includes(searchText)
)
setItemOffset(0);
}, [data, searchText])
It doesn't work, do I have to pass a prop to my components additionally?
greetings.
As I suggested to you, search all the notes with searchText in your App.js and pass the results into the Pagination component and it will solve your problem.
Codesandbox: https://codesandbox.io/s/youthful-thompson-xugs0c
Edit
All changes are as per what we talked about in the email.
Codesandbox: https://codesandbox.io/s/green-fast-3k76wx
Search and pagination do not play well together, one of the common solutions is to jump to page 1 each time the filter term changes.
So use an useEffect on searchText to filter data and reset itemOffset to 0, then redo pagination as if the data changed.
The user will jump to page 1 at each keystroke of the search, then he can navigate pages (if there are more than one). This will lead to a less confusing UX.
-1
Hi I am new in ReactJS
I want to get a Image with spesific Text in caption from Instagram graph api.For example if caption from image has "yes" word in Instagram then must show in homepage.I try to define Mypost with const myPost = contain yes word but i don't get any return.thank you for your help.
import React,{useState} from 'react'
import axios from 'axios';
import ReactDOM from "react-dom";
function Deneme() {
// component variables go here
const [Posts, setPosts] = useState(null);
const fetchData = async () => {
const response = await axios.get(`https://graph.instagram.com/me/media?fields=id,caption,media_url,permalink,username&access_token=IGQV....`)
setPosts(response.data.data)
};
return (
<div className="Deneme">
<h1>Game of Thrones Posts</h1>
<h2>Fetch a list from an API and display it</h2>
{/* Fetch data from API */}
<div>
<button className="fetch-button" onClick={fetchData}>
Fetch Data
</button>
<br />
</div>
{/* Display data from API */}
<div className="Posts">
{Posts &&
Posts.map((posts, index) => {
const myPost = posts.caption.contains("yes");
const cleanedDate = new Date(posts.released).toDateString();
console.log(cleanedDate)
return (
<div className="posts" key={index}>
<h3>posts {index + 1}</h3>
<h2>{myPost.username}</h2>
<div className="details">
<p>{myPost.caption} </p>
<img className="post_img" src={myPost.media_url} alt="image"/>
</div>
</div>
);
})}
</div>
</div>
);
}
export default Deneme
**
enter code here
**
You are not calling the fetchData function anywhere. Call it when the component first renders with the useEffect hook:
useEffect(() => {
fetchData();
}, []);
More on useEffect: https://reactjs.org/docs/hooks-effect.html
I am waiting for the data (when the user submit) i fetch the data then return the Temperature with useState() but i wanted to return a header with it like Temperature:12°C.
Something else is that i wanna round the temperature to 2 decimal places but i don't know how to do so
here is my code:
import axios from 'axios';
import React from 'react'
import {useState, useEffect} from 'react'
import './style.css'
import rain from './use1.png'
function App() {
const [name,setName] = useState('Cairo')
const [res, setRes] = useState(null)
const [pic, setPic] = useState(null)
const [temp, setTemp] = useState('')
const getApi = e => {
axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${name}&appid=my_key`)
.then(response=> {
console.log(response.data);
setRes(response.data.name)
setTemp(response.data.main.feels_like-273.15+'°C');
Math.round(temp)
setPic(`https://openweathermap.org/img/w/${response.data.weather[0].icon}.png`)
})}
const handleChange = e => {
setName(e.target.value);
};
return (
<div>
<img className="wallpaper" src={rain}></img>
<div className="content">
<input placeholder="Search.." className="input" onChange={handleChange}></input>
</i>
</div>
<div className="content2">
<h1 className="name">{res}</h1>
<img src={pic}></img>
<h1 className="temp">{temp}</h1>
</div>
</div>
);
}
export default App;
Add a useEffect hook so your component re-renders after your temp state changes.
useEffect(() => {}, [temp]);
In order to round to two decimal places...well, usually I don't like telling people this but that's an extremely easy thing to find out from just using Google or another search engine.
JavaScript math, round to two decimal places
You could do it like:
`Temperature ${(response.data.main.feels_like-273.15).toFixed(2)} °C`
You can do like this
const [temp, setTemp] = useState('')
setTemp(response.data.main.feels_like-273.15+'°C');
return (
<div>
<h1 className="temp"> Temperature {temp?.toFix(2)}</h1>
</div>
)
Could you please provide the full component's code, or at least where is response coming from? Anyway, If the response is being passed from a parent component, then I see no reason to use useState at all.
But if you are fetching the data in the same component, then you need to fetch the data asynchronously:
function component(){
const [temp, setTemp] = useState('Loading temperature...')
useEffect(() => {
fetchTemp().then((response) => {
setTemp(response.data.main.feels_like-273.15+'°C');
})
}, [])
return (
<div>
<h1 className="temp">{temp}</h1>
</div>
)
}
About rounding the number, you can use toFixed(decimals) method.
Example:
let number = 900.1234
console.log(number.toFixed(2))
I am trying to build a basic web app where a user can search for subreddits using the Reddit API.
However, while I can console.log the data I need from the API I cannot seem to figure out how to display it.
import React, { useState, useEffect } from "react";
import Amplify, { API, graphqlOperation } from "aws-amplify";
import aws_exports from "./aws-exports";
import { withAuthenticator, AmplifySignOut } from '#aws-amplify/ui-react';
import awsconfig from "./aws-exports";
import './App.css'
import axios from 'axios'
import CharacterGrid from './components/CharacterGrid'
import SearchBar from './components/SearchBar'
Amplify.configure(awsconfig);
const App = () => {
const [items, setItems] = useState([])
const [isLoading, setIsLoading] = useState(true)
const [query, setQuery] = useState('')
useEffect(() => {
const fetchItems = async () => {
setIsLoading(true)
const result = await axios(
`https://www.reddit.com/subreddits/search.json?q=${query}`
)
setItems(result.data)
setIsLoading(false)
}
fetchItems()
}, [query])
return (
<div className='container'>
<AmplifySignOut/>
<SearchBar style={{ marginTop: "6%" }} getQuery={(q) => setQuery(q)} />
<CharacterGrid isLoading={isLoading} items={items} />
</div>
)
}
export default withAuthenticator(App)
The child component CharacterGrid looks like this:
import React from 'react'
import CharacterItem from './CharacterItem'
const CharacterGrid = ({items, isLoading}) => {
return
isLoading
? (<h1>Loading ...</h1>)
: (
<section className='cards'>
<p>{items.data}</p> //this does not work
<p>{items.children}</p> //this does not work either
</section>
)
}
export default CharacterGrid
All I want to do is show the names of the subreddits that are returned from the API for the query string the user enters. Where am I going wrong? I have also tried converting to JSON, and mapping through the responses using .map() but I keep getting errors no matter what I try. Where am I going wrong?
However, while I can console.log the data I need from the API I cannot seem to figure out how to display it.
Because Reddit API returns an array of subreddits you should use map() function to iterate over the array and convert each item into React element.
items.map(i => (
<li key={i.data.display_name_prefixed}>
{i.data.display_name}
</li>
))
All I want to do is show the names of the subreddits that are returned from the API for the query string the user enters.
You need to inspect the data schema yourself and scrape the response properly.
Here is working example:
const { useState, useEffect } = React;
const App = () => {
const [items, setItems] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [query, setQuery] = useState("");
useEffect(() => {
setIsLoading(true);
if (query.length >= 3) {
axios(`https://www.reddit.com/subreddits/search.json?q=${query}`)
.then(response => setItems(response.data.data.children))
.catch(error => console.log("Error", error));
}
setIsLoading(false);
}, [query]);
return (
<div>
<input type="text" value={query} onChange={e => setQuery(e.target.value)} />
<CharacterGrid items={items} isLoading={isLoading} />
</div>
);
}
const CharacterGrid = ({ items, isLoading }) => {
return isLoading ? (
<h1>Loading ...</h1>
) : (
<ul>
{items.map(i => (
<li key={i.data.display_name_prefixed}>
{i.data.display_name} ({i.data.display_name_prefixed})
</li>
))}
</ul>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script>
<div id="root"></div>
In order to loop through the elements and e.g: print the title, you could do the following.
items.data.children.map(child => <p> child.data.title </p>)
According to the response provided by reddit,
reddit response