So I have 6 dropdown components in FilterSideBar component, all with different values in select, for example, one dropdown contains values of all car makes, other contains each model value. My main goal is to have all cars fetched on a first render and then filter the array according to selected value from dropdown, rerender cars component and display only cars of that make. I used the useMemo aprroach and it works but it isnt good solution if you have more dropdowns and its all round bad practise to useMemo with arrays. Here is my code. I s there alternative to this approach without using useRef or useMemo hooks?
import "./CarOffers.css"; import axios from "axios"; import Cars from "./Cars"; import CarSlider from "./CarSlider"; import Search from "./Search"; import FilterSideBar from "./FilterSideBar" import CarAlignment from "./CarAlignment"; import DisplayCars from "./DisplayCars"; import React, { useState, useMemo, useEffect } from "react"; import SortingCars from "./SortingCars"; import Pagination from "./Pagination";
const CarOffers = () => {
const [carsList, setCarsList] = useState([]);
const [loading, setLoading] = useState(false);
const [selectedMake, setSelectedMake] = useState();
useEffect(() => {
const fetchCars = async () => {
setLoading(true);
const res = await axios.get(url);
setCarsList(res.data);
setLoading(false);
}
fetchCars()}, []);
const getFilteredList = () => {
if(!selectedMake) {
return carsList
}
return carsList.filter((car) => car.make === selectedMake) }
var filteredList = useMemo(getFilteredList, [ selectedMake, carsList ]);
const handleMakeChange = (select) => {
setSelectedMake(select.value) }
return (
<div className="mka__wrapper-car-offers">
<div className="mka__container">
<div className="mka__content-car-offers">
<div className="mka__content-grid-offers">
<div className="item1">
< CarSlider/>
<div className="mka-responsive-item">
<div className="mka-sorting-div__offers">
<DisplayCars/>
<SortingCars/>
</div>
<CarAlignment/>
</div>
</div>
<div className="item2">
<div className="mka__side-bar-divider">
<h6>FAHRZEUGSUCHE</h6>
<div className="mka__sidebar-divider"></div>
<Search
carsList={carsList}/>
</div>
<div className="mka__sidebar-detailed-search">
<h6>DETAILSUCHE</h6>
<div className="mka__sidebar-divider"></div>
<FilterSideBar
carsList={carsList}
handleMakeChange={handleMakeChange} />
<button className="btn shorter left-alignment">
<svg width="180px" height="60px" viewBox="0 0 180 60" className="border">
<polyline points="179,1 179,59 1,59 1,1 179,1" className="bg-line" />
<polyline points="179,1 179,59 1,59 1,1 179,1" className="hl-line" />
</svg>
<span id="btn-txt">Zurucksetzen</span>
</button>
</div>
</div>
<div className="item3">
<Cars filteredList={filteredList} loading={loading}/>
</div>
</div>
</div>
</div>
</div> ) }
export default CarOffers;
Related
I'm trying to make a dropdown menu like this
-title 1
|-> "lists of items with a href attached"
-title 2
|-> "lists of items with a href attached"
-title 3
|-> "lists of items with a href attached"
Right now my code is like this
footerMenu.js
import { useState } from "react";
import FooterItem from "./FooterItem";
const FooterMenu = (props) => {
return (
<>
<div className="dropdown-menu shadow-lg shadow-slate-300 ml-[40vw] px-12">
<ul className="list-none">
<FooterItem val={"About Us"} />
<FooterItem val={"Careers"} />
<FooterItem val={"Social Impact"} />
<FooterItem val={"For Business Partners"} />
<FooterItem val={"Order and Pickup"} />
</ul>
</div>
</>
);
};
export default FooterMenu;
footerItem.js
import { useState } from "react";
import { FooterList } from "./FooterList";
const FooterItem = (props) => {
const [open, setOpen] = useState(false);
const showDropdown = () => {
setOpen(!open);
};
return (
<li onClick={showDropdown} className="menu-head p-5">
<h2 className="text-xl font-semibold mb-5">{props.val}</h2>
<ul
className={`menu-item relative px-1 gap-y-5 ${
open ? "open-list" : "close-list"
}`}
>
<FooterList />
</ul>
</li>
);
};
export default FooterItem;
and footerList.js
import axios from "axios";
export const FooterList = async () => {
let response = await axios.get(`http://localhost:5000/footerMenu`);
return response.data[0].content.map((val) => {
return (
<>
<li>
<a href={val.link}>
{val.subtitle}
</a>
</li>
</>
);
});
my plan was adding the lists of items for each menu title in a database, and then using axios to get the list but it says objects are not valid as a react child(found: Object Promise])
this is the db i made
i don't know if there is a simpler way of making this dropdown menu
You must use hooks to call async function in react functioal component.
import { useState, useEffect } from "react";
import axios from "axios";
export const FooterList = () => {
const [footerData, setFooterData] = useState();
useEffect(() => {
axios.get(`http://localhost:5000/footerMenu`)
.then((response) => setFooterData(response.data[0].content));
}, [])
return footerData ? footerData.map((val) => {
return (
<li>
<a href={val.link}>
{val.subtitle}
</a>
</li>
);
}) : <LoadingComponent />;
}
I need to fetch data from the MongoDB collection after the user clicks the id properties of the document
[frontend][1]
[1]: https://i.stack.imgur.com/fmW1N.jpg
import { useState, useEffect } from "react";
import { Link } from "react-router-dom";
const ViewVehicles = () => {
const [vehicles, setVehicles] = useState(null);
useEffect(() => {
const fetchvehicles = async () => {
const response = await fetch("/headofDeployement/registerVehicle");
const json = await response.json();
if (response.ok) {
setVehicles(json);
}
};
fetchvehicles();
}, []);
return (
<div className="container ">
<div className="row ">
<div className="col justify-content-center align-center">
<h4>Vehicles Registered</h4>
{vehicles &&
vehicles.map((vehicle) => (
<ul key={vehicle._id}>
<a href="" className="text-danger">
{vehicle._id}
</a>
</ul>
))}
</div>
</div>
</div>
);
};
export default ViewVehicles;
I'm not sure if I understand correctly but you should use the Link component you imported from react-router-dom.
For further reading and methodology of how this use case can be handled, check: https://v5.reactrouter.com/web/example/url-params
Compiled with problems:X
ERROR
src\component\Products.jsx
Line 8:34: React Hook "useState" is called in function "getAllProducts" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use" react-hooks/rules-of-hooks
I'm trying to use useState, what is the best way to fetch the data from database to frontend
import React, { useState } from 'react';
import { NavLink } from 'react-router-dom';
import DATA from '../Data';
const getAllProducts = () => {
const [products, getproducts] = useState({
title : '',
price : '',
image : ''
});
const {title, price, image}= products;
let getproduct = fetch('http://localhost:6000/products/allProducts', {
method : 'GET',
headers : {
'Content-Type':'application/json'
},
body : JSON.stringify({
title, price, image
})
})
const cardItem = (item) => {
return(
<div className="card mx-3 my-5 py-3 px-2" key={item.id} style={{width: "15rem"}} id="cards">
<img src={item.image} className="card-img-top" alt={item.title} />
<div className="card-body text-center">
<h5 className="card-title fw-bolder" id="para">{item.title}</h5>
<p className="lead fw-bold" id="para">${item.price}</p>
<NavLink to={`products/${item.id}`} className="btn btn-outline-danger fw-bolder px-5 rounded-pill" id="para">Buy Now</NavLink>
</div>
</div>
);
}
return (
<div>
<div className="container py-2 mt-5 pt-5">
<div className="row">
<div className="col-12 text-center">
<h1 className="display-6 fw-bolder text-center" id="late">Latest Collections</h1>
<hr/>
</div>
</div>
</div>
<div className="container" id="products">
<div className="row justify-content-around">
{getproduct.map(cardItem)}
</div>
</div>
</div>
);
}
export default getAllProducts;
Hi
First I notify you of errors in your code and then expose you a solution:
In getAllProducts you use a useState but you can't use it this way, it's not a React component.
You also call getAllProducts.map but getAllProducts doesn't return any data array
In your useState the initial value represents ONLY one object of your data array
I would advise you this one , it's near of what you have done.
We create a method to get the data, a state to store the data and we display them conditionally
In my example below I use the axios library, it is an alternative to the fetch method that you use but the principle remains the same with the fetch method (except for one line of code)
I hope it helps you
import React , {useState,useEffect} from 'react'
import axios from 'axios'
const getAllProducts = async ()=>{
//Here is the fetch method
try{
const fetchQuery = await axios.get('my-url')
return fetchQuery.data
}
catch(error){
console.log(error)
}}
const CardItem = (props)=>(
//here you card component that will be mapped
<div>
<p>{props.data.title}</p>
<p>{props.data.price}</p>
</div>
)
const MappedCards = ()=>{
//Our initial state is a empty array
const [allProducts,setProducts] = useState([])
useEffect(()=>{
// I use the hook useEffect so when the MappedCards component is mounted
// I can fetch data and use the setProducts method
const initProducts = async ()=>{
const data = await getAllProducts()
setProducts(data)
}
//I call the method to initProducts
initProducts()
},[])
// I can even make something really cool here
if(allProducts.length === 0){
return <span>Loading data...</span>
}
// Now when allProducts will be filled with data I'll show this
return (<div className="my-container">
<h1>My shop</h1>
{allProducts.map(product => (<CardItem key={product.id} data={product} />}
</div>)
}
export MappedCards
I need your help with an app that I am building. It has a forum page and I have some issues with the forum and post components.
I am trying to pass the id of the post that the user clicked on, with history.push so on the post page the id in the url that I try to get with useParams, has the value of the one I send with history.push. The purpose is for some queries I do so I show the post with its comments.
For now the layout isn’t great because I have to make this feature work.
I do not understand why it doesn’t. My console.logs show null or undefined which make no sense to me.
Thank you if you can help me with this.
Here you have two routes present in the App component. It is important for the last route, the Post one were I use :id so I can get it with useParams.
{/* Route for Trainings Wakeup Rebirth */}
<Route path='#forum' exact component={TrainingsWakeupRebirth} />
<Route path='#forum/:id' exact component={Post} />
Here you have the entire code of the Forum page. Like that you can see how I use history.push to send the value.id of the post to the Post component and the way the component itself is built.
import React, { useState, useEffect, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import ReactPaginate from "react-paginate";
import Post from "../Post/Post";
import './TrainingsWakeupRebirth.scss';
import axios from "axios";
const TrainingsWakeupRebirth = (props) => {
let history = useHistory();
// const forumSectionRef = useRef();
// const postSectionRef = useRef();
const forumSection = document.getElementById('forum-block-wrapper');
const postSection = document.getElementById('post-section');
const showPost = () => {
if (forumSection.style.display === 'block') {
return forumSection.style.display = 'none',
postSection.style.display = 'block';
} else {
return forumSection.style.display = 'block',
postSection.style.display = 'none';
}
}
const [listOfPosts, setListsOfPosts] = useState([]);
const [pageNumber, setPageNumber] = useState(0);
const postsPerPage = 2;
const pagesVisited = pageNumber * postsPerPage;
const displayPosts = listOfPosts.slice(pagesVisited, pagesVisited + postsPerPage).map((value, key) => {
const forParams = () => {
return history.push(`#forum/${value.id}`);
}
const executeAll = () => {
forParams();
showPost();
if(forParams()) {
let id = value.id;
return id;
}
}
return (
<div key={key}>
<div className="topic-row" onClick={() => {executeAll()}}>
<div className="topic-title">{value.title}</div>
<div className="topic-image">
<img src={value.image} alt=""></img>
</div>
<div className="topic-message">{value.postText}</div>
</div>
</div>
);
});
const pageCount = Math.ceil(listOfPosts.length / postsPerPage);
const changePage = ({selected}) => {
setPageNumber(selected);
};
useEffect(() => {
axios.get("http://localhost:3001/posts").then((response) => {
setListsOfPosts(response.data);
});
}, []);
console.log(listOfPosts);
return (
<div className="forum" id="forum">
<div className="forum-section-wrapper page" id="forum-wrapper">
<div className="fluid-grid">
<div className="row">
<div className="col-12">
<div className="title">
<h1><span className="first-title-part">Krishna</span><span className="second-title-part">Hara</span></h1>
</div>
<div className="quote">
<span className="quote-left">FORUM</span><span className="quote-right">Eco Village</span>
</div>
</div>
</div>
<div className="row">
<div className="col-12">
<div className="forum-block-wrapper" id="forum-block-wrapper">
{displayPosts}
<ReactPaginate
previousLabel={"Previous"}
nextLabel={"Next"}
pageCount={pageCount}
onPageChange={changePage}
containerClassName={"paginationBttns"}
previousLinkClassName={"previousBttn"}
nextLinkClassName={"nextBttn"}
activeClassName={"paginationActive"}
/>
</div>
</div>
</div>
</div>
</div>
<div className="post-section" id="post-section">
<div className="fluid-grid">
<div className="row">
<div className="col-12">
<Post />
</div>
</div>
</div>
</div>
</div>
)
};
export default TrainingsWakeupRebirth;
Here is some code from the Post component, so you can see the code that should work but doesn't. Also the console.log(id)
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import axios from "axios";
const Post = (props) => {
let { id } = useParams();
const [postObject, setPostObject] = useState({});
const [comments, setComments] = useState([]);
const [newComment, setNewComment] = useState("");
console.log(id);
useEffect(() => {
axios.get(`http://localhost:3001/posts/byId/${id}`).then((response) => {
console.log(response);
setPostObject(response.data);
});
axios.get(`http://localhost:3001/comments/${id}`).then((response) => {
setComments(response.data);
});
}, [id]);
const addComment = () => {
axios.post("http://localhost:3001/comments", {
commentBody: newComment,
Postid: id,
})
.then((response) => {
const commentToAdd = { commentBody: newComment };
setComments([...comments, commentToAdd]);
setNewComment("");
});
};
console.log(postObject);
return (
<div className="post-section-wrapper">
{/* <div>
<div className="title">
{postObject.title}
</div>
<div className="image">
<img src={postObject.image}></img>
</div>
<div className="message">
{postObject.postText}
</div>
</div> */}
<div className="comments-wrapper">
<div className="">
<input
type="text"
placeholder="Comment..."
autoComplete="off"
value={newComment}
onChange={(event) => {
setNewComment(event.target.value);
}}
/>
<button onClick={addComment}> Add Comment</button>
</div>
<div className="comments-row">
{comments.map((comment) =>
(
<div key={comment.id} className="comment">
{comment.commentBody}
</div>
)
)}
</div>
</div>
</div>
);
}
export default Post;
Thank you very very much!!!
#DrewReese and #JoelHager Thank you so much for checking my code and for your advice. In the meantime I found out that we can pass to a component, aside from the pathname, other values with history.push that we retrieve by using useLocation in the component that we want to. I will answer my own question and add the code.
Here is my Forum component, I prefer adding the entire code so everything is clear. In forParams you will see how I pass the value that I need with useHistory and the attribute state and detail.
import React, { useState, useEffect, useRef } from 'react';
import { useHistory } from 'react-router-dom';
import ReactPaginate from 'react-paginate';
import Post from '../Post/Post';
import './TrainingsWakeupRebirth.scss';
import axios from 'axios';
const TrainingsWakeupRebirth = (props) => {
let history = useHistory();
// const forumSectionRef = useRef();
// const postSectionRef = useRef();
const forumSection = document.getElementById('forum-block-wrapper');
const postSection = document.getElementById('post-section');
const showPost = () => {
if (forumSection.style.display === 'block') {
return forumSection.style.display = 'none',
postSection.style.display = 'block';
} else {
return forumSection.style.display = 'block',
postSection.style.display = 'none';
}
}
const [listOfPosts, setListsOfPosts] = useState([]);
const [pageNumber, setPageNumber] = useState(0);
const postsPerPage = 2;
const pagesVisited = pageNumber * postsPerPage;
const displayPosts = listOfPosts.slice(pagesVisited, pagesVisited + postsPerPage).map((value, key) => {
const forParams = () => {
history.push(
{
pathname: `#forum#${value.id}`,
state: { detail: value.id }
}
);
}
const executeAll = () => {
forParams();
showPost();
}
return (
<div key={key} onClick={() => {executeAll()}}>
<div className="topic-row">
<div className="topic-title">{value.title}</div>
<div className="topic-image">
<img src={value.image} alt=""></img>
</div>
<div className="topic-message">{value.postText}</div>
</div>
</div>
);
});
const pageCount = Math.ceil(listOfPosts.length / postsPerPage);
const changePage = ({selected}) => {
setPageNumber(selected);
};
useEffect(() => {
axios.get("http://localhost:3001/posts").then((response) => {
setListsOfPosts(response.data);
});
}, []);
console.log(listOfPosts);
return (
<div className="forum" id="forum">
<div className="forum-section-wrapper page" id="forum-wrapper">
<div className="fluid-grid">
<div className="row">
<div className="col-12">
<div className="title">
<h1><span className="first-title-part">Krishna</span><span className="second-title-part">Hara</span></h1>
</div>
<div className="quote">
<span className="quote-left">FORUM</span><span className="quote-right">Eco Village</span>
</div>
</div>
</div>
<div className="row">
<div className="col-12">
<div className="forum-block-wrapper" id="forum-block-wrapper">
{displayPosts}
<ReactPaginate
previousLabel={"Previous"}
nextLabel={"Next"}
pageCount={pageCount}
onPageChange={changePage}
containerClassName={"paginationBttns"}
previousLinkClassName={"previousBttn"}
nextLinkClassName={"nextBttn"}
activeClassName={"paginationActive"}
/>
</div>
</div>
</div>
</div>
</div>
<div className="post-section" id="post-section">
<div className="fluid-grid">
<div className="row">
<div className="col-12">
<Post />
</div>
</div>
</div>
</div>
</div>
)
};
export default TrainingsWakeupRebirth;
In the Post component with useLocation and useEffect I get location.state.detail which is the id of the Post, that with useState I set to the constant postId.
import React, { useEffect, useState } from "react";
import { useParams, useHistory, useLocation } from "react-router-dom";
import axios from "axios";
import './Post.scss';
const Post = (props) => {
// let { id } = useParams();
const location = useLocation();
const [postId, setPostId] = useState();
useEffect(() => {
console.log(location.pathname); // result: '#id'
if(location.state) {
console.log(location.state.detail); // result: postId
setPostId(location.state.detail);
}
}, [location]);
const [postObject, setPostObject] = useState({});
const [comments, setComments] = useState([]);
const [newComment, setNewComment] = useState("");
// console.log(id);
useEffect(() => {
axios.get(`http://localhost:3001/posts/byId/${postId}`).then((response) => {
console.log(response.data);
setPostObject(response.data);
});
axios.get(`http://localhost:3001/comments/${postId}`).then((response) => {
setComments(response.data);
});
}, [postId]);
const addComment = () => {
axios.post("http://localhost:3001/comments", {
commentBody: newComment,
Postid: postId,
})
.then((response) => {
const commentToAdd = { commentBody: newComment };
setComments([...comments, commentToAdd]);
setNewComment("");
});
};
if(postObject !== null) {
console.log(postObject);
}
return (
<div className="post-section-wrapper">
{postObject !== null
?
<div className="posts-wrapper">
<div className="title">
{postObject.title}
</div>
<div className="image">
<img src={postObject.image}></img>
</div>
<div className="message">
{postObject.postText}
</div>
</div>
:
null
}
<div className="comments-wrapper">
<div className="">
<input
type="text"
placeholder="Comment..."
autoComplete="off"
value={newComment}
onChange={(event) => {
setNewComment(event.target.value);
}}
/>
<button onClick={addComment}> Add Comment</button>
</div>
<div className="comments-row">
{comments.map((comment) =>
(
<div key={comment.id} className="comment">
{comment.commentBody}
</div>
)
)}
</div>
</div>
</div>
);
}
export default Post;
While trying to render a functional component and trying to truncate a large paragraph on a map item using item.biography.substr(0, 20).
I have tried different syntaxes without success. Will appreciate any help. Here is my component.
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import axios from 'axios';
import $ from 'jquery';
//import "./styles.css";
function Instructor() {
const [page, setPage] = useState(1);
const [data, setData] = useState(['a', 'b', 'c']);
const [isLoading, setIsLoading] = useState(true);
const loadMoreData = () => {
setPage(page + 1);
};
useEffect(() => {
const fetchData = async () => {
const result = await axios(
'http://www.localhost/ulearn/api/getInstructors',
);
setData(result.data);
};
fetchData();
}, []);
return (
<div>
<h1> API FOR INSTRUCTOR COMPONENT </h1>
{isLoading && <p>Wait I'm Loading comments for you</p>}
{data.length !== 0 && (
<button onClick={loadMoreData}>Load More Data</button>
)}
{data.map((item, index) => (
<div className="col-xl-3 col-lg-4 col-md-6 col-sm-6" key={index}>
<div className="instructor-box mx-auto text-center">
<a href="{{ route(d.view, d.instructor_slug) }}">
<main>
<div className="col-md-12">
<h6 className="instructor-title">{item.first_name}
{item.last_name}
`enter code here`</h6>
<p> {item.biography.substr(0, 20)} </p>
</div>
</main>
</a>
</div>
</div>
))}
</div>
);
}
if (document.getElementById('instructor')) {
ReactDOM.render(<Instructor />, document.getElementById('instructor'));
}
It seems like it is trying run the substring method on an undefined property? This could imply that biogarphy could be undefined.
Given that the initial state of data is ['a', 'b', 'c'], it is certain that biography is undefined while waiting for the response from fetchData() in the useEffect() hook.
In that case, you might want to do a null/undefined check and conditionally run the statement with the substr() method only if item.biography has been populated with the response from the useEffect hook
{item.biography && item.biography.substr(0, 20)}
if string can be null you'll get the error
change this line
<p> {item.biography.substr(0, 20)} </p>
to
{!!item.biography && (<p>{item.biography.substr(0, 20)}</p>)}
You need to add a check for biography is not undefined while using substr on it.
Also i suggest you to use .substring() as .substr is deprecated.
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import axios from 'axios';
import $ from 'jquery';
//import "./styles.css";
function Instructor() {
const [page, setPage] = useState(1);
const [data, setData] = useState(['a', 'b', 'c']);
const [isLoading, setIsLoading] = useState(true);
const loadMoreData = () => {
setPage(page + 1);
};
useEffect(() => {
const fetchData = async () => {
const result = await axios(
'http://www.localhost/ulearn/api/getInstructors',
);
setData(result.data);
};
fetchData();
}, []);
return (
<div>
<h1> API FOR INSTRUCTOR COMPONENT </h1>
{isLoading && <p>Wait I'm Loading comments for you</p>}
{data.length !== 0 && (
<button onClick={loadMoreData}>Load More Data</button>
)}
{data.map((item, index) => (
<div className="col-xl-3 col-lg-4 col-md-6 col-sm-6" key={index}>
<div className="instructor-box mx-auto text-center">
<a href="{{ route(d.view, d.instructor_slug) }}">
<main>
<div className="col-md-12">
<h6 className="instructor-title">{item.first_name}
{item.last_name}
`enter code here`</h6>
<p> {item.biography && item.biography.substring(0, 20)} </p>
</div>
</main>
</a>
</div>
</div>
))}
</div>
);
}
if (document.getElementById('instructor')) {
ReactDOM.render(<Instructor />, document.getElementById('instructor'));
}
It is very possible that the content of biography is undefined, so you can add a check by conditionally rendering it to make sure it only displays the biography if biography contains a value or exists.
You can change
<p> {item.biography.substr(0, 20)} </p>
to
{item.biography && <p> {item.biography.substr(0, 20)} </p>}