I can not display data from django rest framework with axios - reactjs

I am still new.
I am making my portfolio.But I got problem.
I am trying to get data from django rest framework with axios. It says I got no error.
I want to display the data in cards components.
But still it does not show data in the browser.
How can I solve this problem?
Thank you in advance.
//App.tsx
const App: React.FC = () => {
const [loading, setLoading] = useState(false);
const [results, setResults] = useState<EventProps[]>([]);
const url = "http://127.0.0.1:8000/events/lists/";
useEffect(() => {
const getEventsData = async () => {
try {
const res = await axios.get<EventProps[]>(url).then((res) => {
setResults(res.data);
setLoading(true);
// console.log(res.data.results.event_id);
console.log(res);
console.log(res.data);
});
} catch (err) {
console.log(err);
}
};
getEventsData();
}, []);
return (
<>
<div className="wholeheader">
<MantineProvider
inherit
theme={{ defaultGradient: { from: "blue", to: "teal", deg: 20 } }}
>
<Group position="apart" grow>
<Center
sx={(theme) => ({
height: 170,
backgroundImage: theme.fn.gradient(),
color: theme.white,
})}
>
<Logo />
<div className="header">
<HeaderTabsColored {...HeaderProps} />
<LoginAndRegiInHeader />
</div>
<div className="searchbar">
<SearchBar />
</div>
</Center>
</Group>
</MantineProvider>
</div>
{loading ? (
<Fragment>loading..</Fragment>
) : (
Object.values(results).map((result: EventProps) => (
<EventsCard
key={result.event_id}
event_id={result.event_id}
title={result.title}
description={result.description}
dateTime={result.dateTime}
capacity={result.capacity}
EventImage1={result.EventImage1}
EventImage2={result.EventImage2}
EventImage3={result.EventImage3}
location={result.location}
host={result.host}
/>
))
)}
<br />
<br />
<Page />
</>
);
};
export default App;
//Events.tsx
[data in the browser][1]
import { EventProps } from "../types/EventsProps";
import { Grid } from "#mantine/core";
import axios from "axios";
import { ThemeContext } from "#emotion/react";
import eventImage from "../Images/Events/eventImage.jpg";
const useStyles = createStyles((theme) => ({
card: {
backgroundColor:
theme.colorScheme === "dark" ? theme.colors.dark[7] : theme.white,
},
section: {
borderBottom: `1px solid ${
theme.colorScheme === "dark" ? theme.colors.dark[4] : theme.colors.gray[3]
}`,
paddingLeft: theme.spacing.md,
paddingRight: theme.spacing.md,
paddingBottom: theme.spacing.md,
},
like: {
color: theme.colors.red[6],
},
label: {
textTransform: "uppercase",
fontSize: theme.fontSizes.xs,
fontWeight: 700,
},
}));
// {EventImage1, EventImage2, EventImage3, event_id, location, description, capacity, title, host,dateTime}:
const EventsCard: React.FC<EventProps> = (props) => {
const { classes, theme } = useStyles();
const [opened, setOpened] = useState(false);
return (
<Grid>
<Grid.Col span={4} key={props.event_id}>
<Card withBorder radius="md" p="md" className={classes.card}>
<Card.Section>
<Image
className="image"
src={props.EventImage1}
alt={props.title}
height={300}
width={342}
/>
<Image
className="image"
src={props.EventImage2}
alt={props.title}
height={300}
width={342}
/>
<Image
className="image"
src={props.EventImage3}
alt={props.title}
height={300}
width={342}
/>
</Card.Section>
<Card.Section className={classes.section} mt="md">
<Group position="apart">
<Text size="lg" weight={800}>
{props.title}
<br />
{props.dateTime}
</Text>
<Badge size="sm">{props.location}</Badge>
</Group>
<Text size="lg" weight={500}>
定員:{props.capacity}名
</Text>
<Text size="sm" mt="xs">
{props.description}
</Text>
</Card.Section>
<Card.Section className={classes.section}>
<Text mt="md" className={classes.label} color="dimmed">
host
</Text>
<Text size="sm">{props.host}</Text>
</Card.Section>
</Card>
</Grid.Col>
</Grid>
);
};
export default EventsCard;

Related

React fetch - initial state not loading - what can I do?

I have started to learn react two days ago, so I am a complete newbie. I am attempting to create a simple website app that loads beer data (image, name, tagline) from a public API on cards. Upon clicking on the card, it should display description, name, tagline.
My problem is that upon initial load, no data loads - each card only loads after I click on it.after clicking one card twice
It was working fine before I introduced the clicking function and backFacingCard.
I tried several things, including making separate components for each card side but like I said, I am still very new to react and coding in general, so I am not sure if what I do is correct. I would be very grateful for any tips and tricks.
Here is my code for the card component:
const BeerTile = (props) => {
const frontFacingCard = {
src: (
<Card
hoverable
size="small"
style={{
width: 350,
height: 220,
}}
cover={
<img
className="beer_tile_card_img"
alt="beer-bottle"
src={props.beer?.image_url}
/>
}
>
<Meta
className="meta"
title={props.beer?.name}
description={props.beer?.tagline}
/>
</Card>
),
};
const backFacingCard = {
src: (
<Card
hoverable
size="small"
style={{
width: 350,
height: 220,
}}
cover={
<div className="beer-description">{props.beer?.description}</div>
}
>
<Meta
className="meta"
title={props.beer?.name}
description={props.beer?.tagline}
/>
</Card>
),
};
const [card, setCard] = useState(frontFacingCard.src);
const [showsFront, setShowsFront] = useState(true);
const clickHandler = () => {
if (showsFront) {
setCard(backFacingCard.src);
setShowsFront(false);
props.frontSide(showsFront);
} else {
setCard(frontFacingCard.src);
setShowsFront(true);
props.frontSide(showsFront);
}
};
return (
<div
className="beer_tile_card"
onClick={clickHandler}
front={showsFront ? 1 : 0}
>
{card}
</div>
);
};
in your second component you can use useEffect
const [card, setCard] = useState(frontFacingCard.src);
const [showsFront, setShowsFront] = useState(true);
useEffect(()=>{
console.log("frontFacingCard.src",frontFacingCard.src)//check if source is available
setCard(frontFacingCard.src)
},[frontFacingCard.src])
const clickHandler = () => {
if (showsFront) {
setCard(backFacingCard.src);
setShowsFront(false);
props.frontSide(showsFront);
} else {
setCard(frontFacingCard.src);
setShowsFront(true);
props.frontSide(showsFront);
}
};
return (
<div
className="beer_tile_card"
onClick={clickHandler}
front={showsFront ? 1 : 0}
>
{card}
</div>
);
};
you can do this alternate solution
const BeerTile = (props) => {
const FrontFacingCard = () => {
return (
<Card
hoverable
size="small"
style={{
width: 350,
height: 220,
}}
cover={
<img
className="beer_tile_card_img"
alt="beer-bottle"
src={props.beer?.image_url}
/>
}
>
<Meta
className="meta"
title={props.beer?.name}
description={props.beer?.tagline}
/>
</Card>
)
};
const BackFacingCard =()=> {
return (
<Card
hoverable
size="small"
style={{
width: 350,
height: 220,
}}
cover={
<div className="beer-description">{props.beer?.description}</div>
}
>
<Meta
className="meta"
title={props.beer?.name}
description={props.beer?.tagline}
/>
</Card>
)
};
const [showsFront, setShowsFront] = useState(true);
const clickHandler = () => {
setShowsFront(!showFront);
props.frontSide(showsFront);
};
return (
<div
className="beer_tile_card"
onClick={clickHandler}
front={showsFront ? 1 : 0}
>
{
showsFront
? <FrontFacingCard />
: <BackFacingCard />
}
</div>
);
};
Checkout this cleaner solution, that separate back,front and Tile.
const BeerTile = (props) => {
const [front, setFront] = useState(true);
const clickHandler = () => {
setFront(!front)
};
return (
<div
className="beer_tile_card"
onClick={clickHandler}
front={showsFront ? 1 : 0}
>
{front?<FrontFacingCard {...props}/>:<BackFacingCard {...props}/> }
</div>
);
};
const FrontFacingCard=(props)=>
(
<Card
hoverable
size="small"
style={{
width: 350,
height: 220,
}}
cover={
<img
className="beer_tile_card_img"
alt="beer-bottle"
src={props.beer?.image_url}
/>
}
>
<Meta
className="meta"
title={props.beer?.name}
description={props.beer?.tagline}
/>
</Card>
),
};
const BackFacingCard =( props)=>(
<Card
hoverable
size="small"
style={{
width: 350,
height: 220,
}}
cover={
<div className="beer-description">{props.beer?.description}</div>
}
>
<Meta
className="meta"
title={props.beer?.name}
description={props.beer?.tagline}
/>
</Card>
);

I want to click anywhere on the box to navigate me to the post detail page except the buttons. It's buttons should it's own job

import {
Box,
Flex,
Text,
Input,
Image,
useColorModeValue,
useClipboard,
Divider,
IconButton,
HStack,
Menu,
MenuButton,
MenuList,
Portal,
MenuItem,
useToast,
useOutsideClick,
useDisclosure,
} from "#chakra-ui/react";
import {
BsThreeDots,
BsDot,
BsBookmark,
BsFlag,
BsCheckCircle,
} from "react-icons/bs";
import { BsHeart } from "react-icons/bs";
import { AiFillHeart, AiFillMessage } from "react-icons/ai";
import { FaShareSquare } from "react-icons/fa";
import parse from "html-react-parser";
import copyLink from "#/images/copy-link.svg";
import { axiosInstance } from "#/axiosConfig";
import { COLORS } from "../../constants/COLORS";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import { useDispatch, useSelector } from "react-redux";
import { Link, useNavigate } from "react-router-dom";
import { addNotice, deleteMyPostSlice } from "../../redux/slices/userSlice";
import { FiEdit } from "react-icons/fi";
import { HiOutlineTrash } from "react-icons/hi";
import {
addComment,
deletePost,
publishPost,
unPublishPost,
} from "../../redux/asyncActions/postAction";
import CustomImage from "../small/CustomImage";
import {
deletePostSlice,
removeBookmarkSlice,
} from "../../redux/slices/postSlice";
import {
EmailShareButton,
FacebookShareButton,
TwitterShareButton,
LinkedinShareButton,
FacebookIcon,
TwitterIcon,
LinkedinIcon,
EmailIcon,
} from "react-share";
import AddPicker from "../small/AddPicker";
import PostTag from "./PostTag";
import LikedPeople from "../small/LikedPeopleModal";
import { useRef } from "react";
import ReportModal from "../common/ReportModal";
dayjs.extend(relativeTime);
var domain = window.location.host;
const NewsFeedPost = ({ data }) => {
const [liked, setLiked] = useState(data?.has_liked);
const [hasFav, setHasFav] = useState(data?.has_favorited);
const [likedCount, setLikedCount] = useState(data?.likers_count);
const [commentInput, setCommentInput] = useState("");
const { isOpen, onOpen, onClose } = useDisclosure();
const userId = useSelector((state) => state.userReducer?.userInfo?.id);
const { hasCopied, onCopy } = useClipboard(
`${domain}/post-detail/${data?.id}`
);
const toast = useToast();
const bg = useColorModeValue("white", COLORS.darkGray);
const borderColor = useColorModeValue(
COLORS.lightGrayBorder,
COLORS.darkGrayBorder
);
const navigate = useNavigate();
const ref = useRef();
const [isModalOpen, setIsModalOpen] = useState(false);
useOutsideClick({
ref: ref,
handler: () => setIsModalOpen(false),
});
const dispatch = useDispatch();
const likeThisPost = async (post_id) => {
try {
const r = await axiosInstance.post(`post/like/${post_id}`);
setLikedCount(r.data.likers_count);
setLiked((prev) => !prev);
} catch (err) {}
};
const bookmarkThisPost = async (post_id) => {
try {
const r = await axiosInstance.post(`post/favorite/${post_id}`);
setHasFav(r.data.favorited);
if (r.data.favorited) {
dispatch(addNotice("This post has been bookmarked"));
} else {
dispatch(addNotice("Bookmark has been removed"));
}
dispatch(removeBookmarkSlice(post_id));
} catch (err) {}
};
const deleteThisPost = (id) => {
dispatch(deletePost(id));
dispatch(deleteMyPostSlice(id));
};
const addMyComment = (e, id) => {
e.preventDefault();
let data = {
post_id: id,
content: commentInput,
};
dispatch(addComment(data));
navigate(`/post-detail/${id}`, { replace: true });
};
const unPublishPosts = (id) => {
dispatch(unPublishPost(id));
dispatch(deletePostSlice(id));
};
const publishPosts = (id) => {
dispatch(publishPost(id));
dispatch(deleteMyPostSlice(id));
};
return (
<Box
bg={bg}
mt="1.5rem"
p="1.5rem"
pt="0.8rem"
borderWidth={1}
borderColor={borderColor}
style={{ borderRadius: "10px" }}
onClick={() => navigate(`/post-detail/${data?.id}`)}
>
<Flex mb="1.5rem" align="center" direction="row" justify="space-between">
<Link to={`/post-detail/${data?.id}`}>
<Text fontWeight="400">{data?.title}</Text>
</Link>
<Menu>
<MenuButton>
<BsThreeDots />
</MenuButton>
<Portal>
<MenuList w="100px" p="3" bg={bg}>
{data?.user.id === userId ? (
<Flex direction={"column"} ml="1rem">
<Link to={`/post-edit/${data?.id}`}>
<Flex className="menuitems">
<FiEdit />
<Text ml="4" fontSize="0.8rem">
Edit
</Text>
</Flex>
</Link>
<Flex
className="menuitems"
onClick={() => deleteThisPost(data?.id)}
>
<HiOutlineTrash />
<Text ml="4" fontSize="0.8rem">
Delete
</Text>
</Flex>
{!data.is_published ? (
<Flex
className="menuitems"
onClick={() => publishPosts(data?.id)}
>
<BsCheckCircle />
<Text ml="4" fontSize="0.8rem">
Publish
</Text>
</Flex>
) : (
<Flex
className="menuitems"
onClick={() => unPublishPosts(data?.id)}
>
<FiEdit />
<Text ml="4" fontSize="0.8rem">
Unpublish
</Text>
</Flex>
)}
<Flex
className="menuitems"
onClick={() => bookmarkThisPost(data?.id)}
>
<BsBookmark color={hasFav ? "lightgreen" : ""} />
<Text ml="4" fontSize="0.8rem">
{hasFav ? "Remove Bookmark" : "Bookmark"}
</Text>
</Flex>
</Flex>
) : (
<Flex direction={"column"} ml="1rem">
<Flex
className="menuitems"
onClick={() => bookmarkThisPost(data?.id)}
>
<BsBookmark color={hasFav ? "lightgreen" : ""} />
<Text ml="4" fontSize="0.8rem">
{hasFav ? "Remove Bookmark" : " Bookmark"}
</Text>
</Flex>
<Flex className="menuitems" onClick={onOpen}>
<BsFlag />
<Text ml="4" fontSize="0.8rem">
Report
</Text>
<ReportModal
modalIsOpen={isOpen}
closeModal={onClose}
type="post"
id={data?.id}
/>
</Flex>
</Flex>
)}
</MenuList>
</Portal>
</Menu>
</Flex>
<Flex direction="row" align="center" justify="space-between">
<Box>
<Flex direction="row" align="center">
<Link to={`/user-profile/${data?.user?.id}`}>
<CustomImage
size="50px"
char={data.user?.firstname.charAt(0)}
imageUrl={data?.user?.photo}
alt={`${data.user?.firstname}'s Avatar`}
role={data?.user?.role}
/>
</Link>
<Flex ml="1rem" direction="column">
<Link to={`/user-profile/${data?.user?.id}`}>
<Text
fontSize={["12px", "13px", "13px", "13px"]}
mb="2px"
fontWeight="500"
>
{data?.user?.firstname} {data?.user?.lastname}
</Text>
</Link>
<Flex direction="row" align="center">
<Text
style={{ color: "#ABAAAF" }}
fontSize={["9px", "9px", "9px", "12px"]}
>
{dayjs(data.created_at).fromNow()}
</Text>
<BsDot
color="#ABAAAF"
fontSize={"20px"}
// fontSize={["14px","14px","15px","24px"]}
ml="4px"
/>
<Flex fontSize="10px" ml="4px">
in{" "}
<Text
ml="1"
cursor="pointer"
color="#FF8053"
onClick={() =>
navigate(`/?category_id=${data?.category?.id}`)
}
>
{data?.category?.name}
</Text>
</Flex>
</Flex>
</Flex>
</Flex>
</Box>
{data.tags && <PostTag tags={data?.tags} />}
</Flex>
<Box className="parseContent" mt="1.5rem" fontSize="12px">
<Link to={`/post-detail/${data?.id}`}>{parse(data.content_html)}</Link>
</Box>
<Divider mt="1rem" mb="0.5rem" />
<Flex
direction="row"
justify={{ base: "start", sm: "space-between" }}
mt="1rem"
align="center"
>
<Box w={{ base: "50%", sm: "50%", md: "70%", lg: "70%" }}>
<Box pos="relative">
<form
onSubmit={(e) => addMyComment(e, data?.id)}
style={{ position: "relative" }}
>
<Input
value={commentInput}
onChange={(e) => setCommentInput(e.target.value)}
fontSize={["9px", "10px", "12px", "12px"]}
placeholder="Add Response..."
// zIndex={0}
/>
<AddPicker setInput={setCommentInput} />
</form>
</Box>
</Box>
<Box width={{ base: "45%", sm: "45%", lg: "40%" }} pl="1.5rem">
<Flex direction="row" justify="space-around" position="relative">
<Flex direction="row" align="center">
<IconButton
onClick={() => likeThisPost(data.id)}
_hover={{ background: "transparent" }}
_active={{ background: "transparent" }}
_focus={{ boxShadow: "none" }}
bg="transparent"
color="#C5D0E6"
children={
liked ? (
<AiFillHeart fontSize={"1.7rem"} color={COLORS.hasLiked} />
) : (
<BsHeart fontSize={"1.4rem"} />
)
}
/>
<Text
color="#ABAAAF"
fontSize="14px"
onClick={() => setIsModalOpen(true)}
cursor="pointer"
>
{likedCount}
</Text>
{isModalOpen && (
<Box ref={ref}>
<LikedPeople />
</Box>
)}
</Flex>
<Link to={`/post-detail/${data?.id}`}>
<DataIconCount icon="AiFillMessage" count={data.comments_count} />
</Link>
<Menu>
<MenuButton
bg="transparent"
color="#C5D0E6"
_hover={{ background: "transparent", color: "#7B6CB4" }}
_active={{ background: "transparent" }}
_focus={{ boxShadow: "none" }}
className="newsfeed-iconbtn"
as={IconButton}
aria-label="Options"
icon={<FaShareSquare fontSize={"1.5rem"} />}
/>
<MenuList bg={bg}>
<MenuItem fontSize="12px">
<HStack align="center" gap="4px">
<FacebookShareButton
url={`${domain}/post-detail/${data?.id}`}
>
<Flex>
<FacebookIcon size={22} />
<Text ml="3">Facebook</Text>{" "}
</Flex>
</FacebookShareButton>
</HStack>
</MenuItem>
<MenuItem fontSize="12px">
<TwitterShareButton url={`${domain}/post-detail/${data?.id}`}>
<Flex>
<TwitterIcon size={22} />
<Text ml="3">Twitter</Text>{" "}
</Flex>
</TwitterShareButton>
</MenuItem>
<MenuItem fontSize="12px">
<LinkedinShareButton
url={`${domain}/post-detail/${data?.id}`}
>
<Flex>
<LinkedinIcon size={22} />
<Text ml="3">LinkedIn</Text>{" "}
</Flex>
</LinkedinShareButton>
</MenuItem>
<MenuItem fontSize="12px">
<EmailShareButton url={`${domain}/post-detail/${data?.id}`}>
<Flex>
<EmailIcon size={22} />
<Text ml="3">Mail</Text>
</Flex>
</EmailShareButton>
</MenuItem>
<MenuItem fontSize="12px">
<HStack
onClick={() => {
onCopy();
toast({
description: "Copied Post Link",
status: "success",
position: "top-right",
});
}}
align="center"
gap="4px"
>
<Image src={copyLink} />
<Text>Copy Link</Text>
</HStack>
</MenuItem>
</MenuList>
</Menu>
</Flex>
</Box>
</Flex>
</Box>
);
};
I
I have a post where there are lots of button. Each button has it's own task. Whenever I click on any white space or anywhere except this buttons, I should get navigated to post details page. So I have assigned navigate function on the onclick of the parent container that is "Box". The issue is that since all children are wrapped in box so clicking on those buttons also navigate . I want to navigate only on white spaces. I wrote a clumsy way of using e.stopPropagation() so buttons click prevent navigate() but still few buttons are navigating. Is there any way of navigating only when anywhere except buttons?
In the click event listener, check if the event current target is not a button.
if(!evt.currentTarget.matches('button'))

React, availableForSale: true to display Text when true

I am using Shopify as my backend and react as my frontend, and when the product.availableforsale is true I want it to print out in stock. Here is the code on my product page.
I have commented on the code where the {product.availableForSale} is in the product page component.
import React, { useEffect, useContext, useState } from "react";
import { useParams } from "react-router-dom";
import { ShopContext } from "../../context/shopContext";
import { Text, Div, Button, Row, Col, Container, Image } from "atomize";
import { Link } from "react-router-dom";
import "./ProductPage.css";
import { Spinner } from 'react-bootstrap';
//Res
// const theme = {
// grid: {
// colCount: 8,
// gutterWidth: 0
// }
// };
const ProductPage = () => {
let { id } = useParams();
const { fetchProductWithId, addItemToCheckout, product, client } = useContext(
ShopContext
);
//Fav
const [favoriteText, setFavoriteText] = useState("Add to Favorite");
//Variants
const [sizeIndex, setSizeIndex] = useState('');
const [posterIndex, setPosterIndex] = useState('');
useEffect(() => {
fetchProductWithId(id);
return () => {};
}, [fetchProductWithId, id]);
if (!product.title) return <div className="prod-spinner-container"><Spinner animation="border" variant="primary" /></div>
//Variants
const selectedVariant = client.product.helpers.variantForOptions(product, {
Size: sizeIndex || product.options[0].values[0].value,
Poster: posterIndex || product.options[1].values[0].value
});
return (
<Container>
<div className={"row"} >
<Div className="prod-img" p="1.5rem">
<Image src={product.images[0].src} w="20rem" p="2rem"/>
</Div>
<div className="prod-size col-12 col-sm-6 " pos="Center" key={product.id}>
<Text className="title-txt"tag="h1" textColor="white" textWeight="500" m={{ y: "2rem" }} >
{product.title}
</Text>
<Text className="title-txt"tag="h1" textColor="white" textWeight="500" m={{ y: "2rem" }} >
{/* Print Out text? */}
{product.availableForSale}
{product.vendor}
</Text>
{/* Selected variant will allow the price to change due to frame size etc */}
<Text className="cost-txt" tag="h3" textColor="white" m={{ y: "2rem" }} textWeight="100">
Price € {selectedVariant?.price} Excl Shipping
</Text>
{/* Poster size */}
<Text>Size (inc)</Text>
<select className="custom-select" value={posterIndex} onChange={e => setPosterIndex(e.target.value)} >
{product.options[1].values.map((item, index) => (
<option value={item.value}>{item.value}</option>
))
}
</select>
<Text>Frame</Text>
<select className="custom-select" value={sizeIndex} onChange={e => setSizeIndex(e.target.value)} >
{product.options[0].values.map((item, index) => (
<option value={item.value}>{item.value}</option>
))
}
</select>
<Button
rounded="lg"
shadow="3"
bg="black500"
m={{ y: "2rem" }}
onClick={() => addItemToCheckout(selectedVariant?.id, 1)}
>
Add to Cart
</Button>
<Button rounded="lg"
shadow="3"
bg="black500"
m={{ y: "2rem" }}
onClick={() => {
// console.log(product);
let favorites = JSON.parse(localStorage.getItem('favorites') || "[]");
const productExists = favorites.find(favorite => favorite.id === product.id);
if(productExists) {
favorites = favorites.filter(favorite => favorite.id !== product.id);
setFavoriteText("Add to Favorite")
localStorage.setItem('favorites', JSON.stringify(favorites));
} else {
favorites = [...favorites, product];
setFavoriteText("Remove from Favorite");
localStorage.setItem('favorites', JSON.stringify(favorites));
}
}}>
{/* <HeartIcon title="Add to Favourites" style={{height: '25px', width: '25px', backgroundColor: "#fff", color: "red" }} /> */}
{favoriteText}
</Button>
</div>
</div>
</Container>
);
};
export default ProductPage;
Any help would be greatly appreciated thanks. Please let me know if more code is needed thanks
If you want only one condition to show Out in Stock then use this
{product.availableForSale &&
<Text className="title-txt"tag="h1" textColor="white" textWeight="500" m={{ y: "2rem" }} >
{/* Print Out text? */}
{product.vendor}
</Text>
}
Or
{product.availableForSale ?
<Text className="title-txt"tag="h1" textColor="white" textWeight="500" m={{ y: "2rem" }} >
{/* Print Out text? */}
{product.vendor}
</Text>
:<div>Available</div>
}
You can create another state to track the download from the server
[isLoading, setIsLoading] = useState(true)
and when displaying data, look at this state
{
!isLoading ? (
<Text
className="title-txt"
tag="h1"
textColor="white"
textWeight="500"
m={{ y: "2rem" }}
>
{/* Print Out text? */}
{product.vendor}
</Text>
) : (
<Loader />
);
}

Why my props are undefined when sending to components?

I have a table in my project and I have an edit / view / add page that I can access from this table. My goal is to send the clicked data to the other component without any problem, but no matter how hard I try, I get an undefined error and the project is broken. I would be glad if you could help.
I am sharing my codes from parent to child component
Table page.
import React, { useState, useEffect, useCallback, useMemo } from "react";
import ManagementTable from '../components/ManagementTable'
import {
getApps,
updateStopRisk,
countLiveCountry,
updateAppShow,
deleteApp,
} from "../api/apiCalls";
import VisibilityIcon from "#material-ui/icons/Visibility";
import DeleteIcon from "#material-ui/icons/Delete";
import EditIcon from "#material-ui/icons/Edit";
import Switch from "#material-ui/core/Switch";
import DeleteModal from "../components/DeleteModal";
import { Link } from "react-router-dom";
const Management = () => {
const [apps, setApps] = useState([]);
const [modalVisible, setModalVisible] = useState(false);
const [currentApp, setCurrentApp] = useState("");
const [appID, setAppID] = useState(0);
const fetchData = useCallback(async () => {
const { data: appsResponse } = await getApps();
const countLiveCountries = await fetchLiveCountriesForApps(appsResponse);
setApps(
appsResponse.map((app, idx) => ({
...app,
countLiveCountry: countLiveCountries[idx],
}))
);
}, []);
useEffect(() => {
fetchData();
}, [fetchData]);
const fetchLiveCountriesForApps = async (appwLive) => {
const countLiveCountries = await Promise.all(
appwLive.map((app) => countLiveCountry(app.appID))
);
return countLiveCountries.map(({ data: liveCountries }) => liveCountries);
};
const removeApp = async () => {
await deleteApp(appID);
setModalVisible(false);
fetchData();
};
const onClickCancel = () => {
setModalVisible(false);
};
const columns = useMemo(() => [
{
Header: "Application Name",
accessor: "app_name",
},
{
Header: "Business Area",
accessor: "businessarea.businessarea_name",
},
{
Header: "Live Plants",
accessor: "countLiveCountry",
},
{
Header: "Line Stop Risk",
accessor: "app_stoprisk",
Cell: ({ row: { original } }) => {
const changeCheck = async (id) => {
await updateStopRisk(id);
fetchData();
};
return (
<input
checked={original.app_stoprisk}
onClick={() => {
changeCheck(original.appID);
}}
id="appStopRisk"
type="checkbox"
style={{ width: 18, height: 18, marginTop: 5 }}
/>
)
},
sortType: (a, b, id) => {
if (a.original[id] > b.original[id]) return -1;
if (b.original[id] > a.original[id]) return 1;
},
},
{
Header: "Actions",
Cell: ({ row: { original } }) => {
const changeTrack = async (id) => {
await updateAppShow(id);
fetchData();
};
return (
<>
<Link
className="btn btn-manage-link btn-sm col-2"
to={{
pathname: `/management/${original.app_name}`,
mode: "view",
id: original.appID
}}
>
<VisibilityIcon></VisibilityIcon>
</Link>
<Link
to={{
pathname: `/management/${original.app_name}`,
mode: "edit",
id: original.appID
}}
className="btn btn-manage-link btn-sm col-2"
>
<EditIcon></EditIcon>
</Link>
<button
onClick={() => {
setModalVisible(true);
setCurrentApp(original.app_name);
setAppID(original.appID);
}}
className="btn btn-manage-link btn-sm col-3"
>
<DeleteIcon></DeleteIcon>
</button>
<Switch
onClick={() => changeTrack(original.appID)}
checked={original.app_show}
className="col-3"
></Switch>
</>
)
},
},
],
[fetchData]
);
return (
<div className="container">
<h2 style={{ float: "left", font: "bold" }}>Management</h2>
<div style={{ float: "right" }}>
<Link className="btn btn-danger btn-sm" to={{ pathname: `/management/add`, mode: "add" }}>
Add New App
</Link>
<Link className="btn btn-danger btn-sm ml-3" exact to="/management/plants">
Plant Management
</Link>
</div>
<ManagementTable columns={columns} data={apps} />
<DeleteModal
message={<strong>{currentApp}</strong>}
variety="app"
onClickCancel={onClickCancel}
onClickOk={removeApp}
visible={modalVisible}
/>
</div>
);
};
export default Management;
The page where I transfer the props.
import React, { useState, useEffect } from "react";
import Accordion from "../components/Accordion";
import Details from '../components/Details'
import {
getByIdApps,
} from "../api/apiCalls";
const ApplicationManagement = (props) => {
const [appById, setAppById] = useState([]);
const { id } = props.location;
const [selectOption, setSelectOption] = useState('add')
useEffect(() => {
getData();
getMode();
}, [])
const getData = async () => {
console.log(props.location.id)
if (props.location.id) {
await getByIdApps(props.location.id).then((response) => setAppById(response.data))
console.log(appById)
console.log(props)
}
else {
setSelectOption('add')
}
}
const getMode = () => props.location.mode ? setSelectOption(props.location.mode) : setSelectOption('add')
const handleOptionChange = (event) => {
console.log(event.target.value)
setSelectOption(event.target.value)
}
return (
<>
<div style={{ margin: 20 }}>
<h1>
{appById.app_shortcode} - {appById.app_fullname}
</h1>
<div className="float-right mb-auto">
<label><input type="radio" value="view" checked={selectOption === 'view'} onChange={handleOptionChange} />View</label>
<label> <input type="radio" value="add" checked={selectOption === 'add'} onChange={handleOptionChange} />Add</label>
<label> <input type="radio" value="edit" checked={selectOption === 'edit'} onChange={handleOptionChange} />Edit</label>
</div>
<br></br>
<div style={{ marginLeft: 50, marginRight: 50 }} >
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Links</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Factory Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Issues Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
<Accordion title={
<div style={{ width: 1350 }}>
<h3>Middleware Management</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}></Accordion>
</div>)
{selectOption === 'add' ? (
<div>
Add Mode
</div>
) : selectOption === 'view' ? (<div>View Mode</div>) : (<div>eidt</div>)}
</div>
</>
);
};
export default ApplicationManagement;
and the section where the details are kept on the ApplicationManagement page (My code is quite long, I just share the problem part.)
import React, { useState, useEffect } from 'react'
import axios from "axios";
import {
getResponsibleTeams,
getBusinessAreas
} from '../api/apiCalls'
const Details = (props) => {
const [rTeams, setrTeams] = useState([]);
const [bAreas, setbAreas] = useState([]);
const { data } = props;
useEffect(() => {
async function fetchData() {
const getrTeams = await getResponsibleTeams();
const getbAreas = await getBusinessAreas();
axios.all([getrTeams, getbAreas]).then(
axios.spread((...allData) => {
const allrTeams = allData[0].data;
const allbAreas = allData[1].data;
setrTeams(allrTeams);
setbAreas(allbAreas);
})
);
}
fetchData();
}, []);
return (
<div>
<div
style={{
float: "left",
width: 1350,
height: 340,
}}
>
<div className="form-group">
<label style={{ float: "left" }} htmlFor="appFullName">
Frontend:{" "}
</label>
<input
id="appFullName"
type="text"
class="form-control"
placeholder="dsfdsdsf"
value={data.frontend.frontend_name} // error here
//onChange={handleInputChange}
name="appShortCode"
style={{ width: 400, marginLeft: 150 }}
/>
</div>
</div>
</div>
)
}
export default Details;
Later I realized that using asynchronous functions caused some problems. I came up with a solution to this and the problem was solved.
Error Code Here :
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>
and the solution to the problem
{appById &&
<Accordion
title={
<div style={{ width: 1350 }}>
<h3>Details</h3>
<hr style={{ backgroundColor: "#aaa" }}></hr>
</div>
}
content={
<Details appID={id} data = {appById}></Details>
}
/>}

How to get ref of google-maps-react map and panto to latlng

My objective is to pan google-maps-react map to a latlng position, after getting a latlong from react-places-autocomplete when a user selects an address suggestion.
I am facing difficulty in setting ref of map from a child functional component, so that I can call map.panTo(location) in the parent functional component.
Following is my Google-Maps and PlaceAutoComplete child Component:
import React, { useEffect } from 'react';
import { Map, GoogleApiWrapper, Marker } from 'google-maps-react';
import { FormGroup, Label, Input, Spinner, Container, Row, Col } from 'reactstrap';
import PlacesAutocomplete from 'react-places-autocomplete';
const InputAndMap = React.forwardRef((props, ref) => {
return (
<div>
<PlacesAutocomplete
value={props.address}
onChange={props.handleInputChange}
onSelect={props.handleInputSelect}
>
{({ getInputProps, suggestions, getSuggestionItemProps, loading }) => (
<div>
<FormGroup>
<Label for="exampleSearch">Search Address</Label>
<Input
{...getInputProps({
className: 'location-search-input',
})}
type="search"
name="search"
id="exampleSearch"
placeholder="Enter Store Location"
/>
</FormGroup>
<div className="autocomplete-dropdown-container">
{loading && (
<div>
<Spinner size="sm" color="primary" />
Loading...
</div>
)}
{suggestions.map(suggestion => {
const className = suggestion.active ? 'suggestion-item--active' : 'suggestion-item';
const style = suggestion.active
? { backgroundColor: '#007bff', cursor: 'pointer', color: 'white' }
: { backgroundColor: '#ffffff', cursor: 'pointer' };
return (
<div
{...getSuggestionItemProps(suggestion, {
className,
style,
})}
>
<span>{suggestion.description}</span>
</div>
);
})}
</div>
</div>
)}
</PlacesAutocomplete>
<Row className="mb-3" style={{ width: '100%', height: '200px' }}>
<Col>
<Map
id="google-map"
ref={ref} // <<=== setting ref here
style={{ width: '100%', height: '200px' }}
google={props.google}
zoom={8}
initialCenter={{ lat: 47.444, lng: -122.176 }}
onClick={(t, map, e) => props.updateMarker(e.latLng, map)}
>
{props.markerLatLong && <Marker position={props.markerLatLong} />}
</Map>
</Col>
</Row>
</div>
);
});
export default GoogleApiWrapper({
apiKey: process.env.REACT_APP_GOOGLE_API_KEY,
libraries: ['places'],
})(InputAndMap);
This is my parent component, where I want to call the map panto function.
import React, { useState, useEffect } from 'react';
import { Button, Form, Spinner, Container } from 'reactstrap';
import { Redirect } from 'react-router-dom';
import { geocodeByAddress, getLatLng } from 'react-places-autocomplete';
import firebase from 'firebase/app';
import NavBarMenu from '../components/NavBarMenu';
import InputAndMap from '../components/InputAndMap';
import fire from '../config/fire';
function StoreScreen(props) {
const [isLoading, setIsLoading] = useState(false);
const [markerLatLong, setMarkerLatLong] = useState(null);
const [city, setCity] = useState('');
const [address, setAddress] = useState('');
const [redirect, setRedirect] = useState(false);
const ref = React.createRef();
const handleInputChange = address => {
setAddress(address);
};
const handleInputSelect = address => {
setAddress(address);
geocodeByAddress(address)
.then(results => {
processCity(results);
getLatLng(results[0])
.then(latLng => {
console.log('Success', latLng);
console.log(ref);// ==============> this return {current: null}
// ref.current.panTo(latLng);// ==> So I am unable to call this
})
.catch(error => console.error('Error', error));
})
.catch(error => console.error('Error', error));
};
return (
<div>
<NavBarMenu isShopKeeper />
<Container className="h-100">
<Form onSubmit={handleSubmit}>
<h5 className="text-center">Add Store</h5>
<InputAndMap
ref={ref}
markerLatLong={markerLatLong}
updateMarker={updateMarker}
handleInputChange={handleInputChange}
handleInputSelect={handleInputSelect}
address={address}
/>
{isLoading ? (
<div className="row mx-auto justify-content-center align-items-center flex-column">
<Spinner color="secondary" />
</div>
) : (
<Button
disabled={!markerLatLong || !city || !address}
className="mb-4"
color="primary"
size="lg"
block
>
Add Store
</Button>
)}
</Form>
</Container>
</div>
);
}
export default StoreScreen;
I am also attaching the image for better visualizing my problem.
Map.panTo changes the center of the map to the given LatLng in Maps JavaScript API. Since you are using google-maps-react library, you can use react states as value of the center parameter of this library to change the value of the Map's center everytime the state changes. In my example code below, I use the code from the getting started docs of react-places-autocomplete and incorporated it with a simple google-maps-react code.
Here's how I declare the state of the center which currently have a value:
state = {
center: {
lat: 40.854885,
lng: -88.081807
},
address: ""
};
Here's the handleSelect event from the react-places-autocomplete library where it geocodes the selected place from the autocomplete. Then you can see that I set the state of the center to the latLng of the geocoded address.
handleSelect = address => {
geocodeByAddress(address)
.then(results => getLatLng(results[0]))
.then(latLng => this.setState({ center: latLng }))
.catch(error => console.error("Error", error));
};
Here's how I call the Map component of the google-maps-react library where the value of center parameter is the value of the state named center.
<Map
className="map"
google={this.props.google}
onClick={this.onMapClicked}
center={this.state.center}
style={{ height: "100%", position: "relative", width: "100%" }}
zoom={13}
/>
Here's a complete code snippet and the working code on how I incorporated the 2 libraries you are using to change the center of the map everytime you choose an address from autocomplete:
import React, { Component } from "react";
import { Map, GoogleApiWrapper } from "google-maps-react";
import PlacesAutocomplete, {
geocodeByAddress,
getLatLng
} from "react-places-autocomplete";
export class MapContainer extends Component {
state = {
center: {
lat: 40.854885,
lng: -88.081807
},
address: ""
};
handleChange = address => {
this.setState({ address });
};
handleSelect = address => {
geocodeByAddress(address)
.then(results => getLatLng(results[0]))
.then(latLng => this.setState({ center: latLng }))
.catch(error => console.error("Error", error));
};
render() {
if (!this.props.loaded) return <div>Loading...</div>;
return (
<div>
<PlacesAutocomplete
value={this.state.address}
onChange={this.handleChange}
onSelect={this.handleSelect}
>
{({
getInputProps,
suggestions,
getSuggestionItemProps,
loading
}) => (
<div>
<input
{...getInputProps({
placeholder: "Search Places ...",
className: "location-search-input"
})}
/>
<div className="autocomplete-dropdown-container">
{loading && <div>Loading...</div>}
{suggestions.map(suggestion => {
const className = suggestion.active
? "suggestion-item--active"
: "suggestion-item";
// inline style for demonstration purpose
const style = suggestion.active
? { backgroundColor: "#fafafa", cursor: "pointer" }
: { backgroundColor: "#ffffff", cursor: "pointer" };
return (
<div
{...getSuggestionItemProps(suggestion, {
className,
style
})}
>
<span>{suggestion.description}</span>
</div>
);
})}
</div>
</div>
)}
</PlacesAutocomplete>
<Map
className="map"
google={this.props.google}
center={this.state.center}
style={{ height: "100%", position: "relative", width: "100%" }}
zoom={13}
/>
</div>
);
}
}
export default GoogleApiWrapper({
apiKey: "YOUR_API_KEY"
})(MapContainer);

Resources