Currently unable to display svg images from API in React app - javascript

Issue that I am currently having is displaying the svg images I am getting from an API for countries. Right now they are showing up as empty divs in the HTML and no errors. I am also using the ReactSVG package and still no luck.
Here below is the Home component which is making the API call and the Card component that fed the content:
import React, {useState, useEffect} from 'react';
import axios from 'axios';
import { Container, Row } from 'react-bootstrap';
import CardComponent from '../components/Card';
const baseURL = 'https://restcountries.eu/rest/v2/all';
const Home = () => {
const [ countries, setCountries ] = useState(null);
useEffect(() => {
console.log('hello')
axios.get(baseURL).then((res) => {
setCountries(res.data);
})
}, []);
return (
<>
<Container>
<Row>
{countries && (
countries.map((country) => {
console.log(country.flag)
return <CardComponent key={country.name}
title={country.name}
image={country.flag}
population={country.population}
region={country.region}
capital={country.capital}/>
})
)}
</Row>
</Container>
</>
)
}
export default Home;
import React from 'react';
import {ReactSVG} from 'react-svg';
import { Card } from 'react-bootstrap';
const CardComponent = (props) => {
const { title, flag, population, region, capital } = props;
return (
<Card>
<ReactSVG src={flag}/>
<Card.Body>
<Card.Title>{title}</Card.Title>
<Card.Text>Population: <span id="Population">{population}</span><br></br></Card.Text>
<Card.Text>Region: <span id="Region">{region}</span><br></br></Card.Text>
<Card.Text>Capital: <span id="Capital">{capital}</span><br></br></Card.Text>
</Card.Body>
</Card>
)
}
export default CardComponent;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Here is also a link to my Git repo for this project https://github.com/codejohnson89/react-countries

In your code, there is some error. Please check this code.
import React, {useState, useEffect} from 'react';
import axios from 'axios';
import { Container, Row } from 'react-bootstrap';
import CardComponent from '../components/Card';
const baseURL = 'https://restcountries.eu/rest/v2/all';
const Home = () => {
const [ countries, setCountries ] = useState(null);
useEffect(() => {
console.log('hello')
axios.get(baseURL).then((res) => {
setCountries(res.data);
})
}, []);
return (
<>
<Container>
<Row>
{countries && (
countries.map((country) => {
console.log(country.flag)
return <CardComponent key={country.name}
title={country.name}
image={country.flag}
population={country.population}
region={country.region}
capital={country.capital}/>
})
)}
</Row>
</Container>
</>
)
}
export default Home;
import React from 'react';
import {ReactSVG} from 'react-svg';
import { Card } from 'react-bootstrap';
const CardComponent = (props) => {
const { title, image, population, region, capital } = props;
return (
<Card>
<img src={image} alt="title" width="80"/>
<Card.Body>
<Card.Title>{title}</Card.Title>
<Card.Text>Population: <span id="Population">{population}</span><br></br></Card.Text>
<Card.Text>Region: <span id="Region">{region}</span><br></br></Card.Text>
<Card.Text>Capital: <span id="Capital">{capital}</span><br></br></Card.Text>
</Card.Body>
</Card>
)
}
export default CardComponent;

Related

ReactJs: How to pass api data to components?

I call api in Home.js file with componentdidmount in class component and i want to render this data in child components with functional components.when i call api in every each child component, its work but when i try to call with props coming only empty array by console.log please help.
import React,{Component} from 'react'
import '../styles/home.css'
import axios from 'axios';
import Teaser from './Teaser'
import Second from './Second'
import Opening from './Opening'
import Menu from './Menu'
export default class Home extends React.Component {
state = {
posts: []
}
componentDidMount() {
axios.get("https://graph.instagram.com/me/media?fields=id,caption,media_url,permalink,username&access_token=IG")
.then(res => {
const posts = res.data.data;
this.setState({ posts });
})
}
render() {
return (
<>
<Teaser/>
<Second/>
<Opening/>
<Menu posts = {this.state.posts}/>
</>
)
}
}
import React from 'react'
import axios from 'axios';
function Menu(props) {
const {posts} = props;
console.log(props);
return (
<>
{posts && posts.map(
(post) =>
post.caption.includes('#apegustosa_menu') &&
post.children.data.map((x) => (
<div className="menu_item" key={x.id}>
<img className="menu_img" src={x.media_url} alt="image" />
</div>
)),
)}
</>
)
}
export default Menu
Here you go:
return (
<>
{
posts && posts.map(post => (
post.caption.includes("#apegustosa_menu") && post.children.data.map(x => {
return <img src={x.media_url} alt="img"></img>
})
))
}
</>
)

Object is undefined when trying to fetch it using useContext()

I am very new to React and was trying to make a context in React so that in my notes app such that I can trigger my custom made alert for relevant user activity but when I am trying to use the values from the context using useContext I am getting error : "Cannot destructure property 'alert' of 'Object(...)(...)' as it is undefined."
Here's the code:-
Creating Context
import React from 'react';
const AlertContext = React.createContext(null);
export default AlertContext;
Populating Value to the Context
import React,{useState} from 'react';
import AlertContext from "./AlertContext";
const ShowAlert = (props)=>{
const [alert,setAlert] = useState(null);
const showAlert = (message,type)=>{
setAlert({
msg:message,
type:type
})
setTimeout(()=>{
setAlert(null);
},3000);
}
return(
<AlertContext.Provider value={{alert,showAlert}}>
{props.children}
</AlertContext.Provider>
)
}
export default ShowAlert;
Trying to use the values
import React, { useContext } from "react";
import { Navbar, Button, Nav } from "react-bootstrap";
import { Link, useHistory } from "react-router-dom";
import ShowAlert from "../contexts/ShowAlert";
import MyAlert from "./MyAlert";
function Header() {
const {alert} = useContext(ShowAlert);
let history = useHistory();
const handleLogout = () => {
localStorage.removeItem("token");
history.push("/login");
};
return (
<>
<header>
<Navbar collapseOnSelect expand="lg" className="header">
<Navbar.Brand className="heading">
<Link to="/" className="headerLink">
Note Cloud
</Link>
<i className="fas fa-cloud-upload-alt cloudIcon"></i>
</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="me-auto"></Nav>
{localStorage.getItem("token") && (
<Nav>
<Nav.Link>
<Button variant="primary" size="lg" onClick={handleLogout}>
Logout
</Button>
</Nav.Link>
</Nav>
)}
</Navbar.Collapse>
</Navbar>
</header>
<MyAlert alert={alert}></MyAlert>
</>
);
}
export default Header;
Edit:- MyAlert Component
import React, { useContext } from "react";
import { Alert } from "react-bootstrap";
import ShowAlert from "../contexts/ShowAlert";
const MyAlert = (props) => {
const {alert} = useContext(ShowAlert);
const capitalize = (word) => {
if(word==="danger")
{
word = "error";
}
const lower = word.toLowerCase();
return lower.charAt(0).toUpperCase() + lower.slice(1);
};
return (
<div style={{ height: "50px" , width:"100%"}}>
{alert && (
<Alert
variant={alert.type}
>
<Alert.Heading>{capitalize(alert.type)}</Alert.Heading>
<p>{capitalize(alert.msg)}</p>
</Alert>
)}
</div>
);
};
export default MyAlert;
Error That I am getting
Try doing the Context like this instead of null.
import React from "react";
const AlertContext = React.createContext({
alert: {},
setAlert: (alert) => {},
});
export default
i think your export is the fail
export const AlertContext = React.createContext({})
or as well you can try:
< AlertContext.Consumer>
{(context) => {
console.log(context)
}}
</AlertContext.Consumer>

Material-UI ListItem as Link Component Changes URL but Not Rendering Component

This is my first time asking a question here, but I am truly stumped.
I'm coding a navbar for my school project website. I'm using Material-UI's List component within the Appbar component. There are two issues I'm seeing: 1) the initial onClick will cause the route to path to '/' and 2) the second onClick will change to the proper route, but not render the desired component. Please see a gif of the issue at the bottom if it helps.
I have been working at this for a few days now, and I am not sure what I am missing 😔
Here is my code for the List component:
PageList.jsx
import React from "react";
import clsx from "clsx";
import { makeStyles } from "#material-ui/core/styles";
import useMediaQuery from "#material-ui/core/useMediaQuery";
import { List, ListItem, ListItemText, ListItemIcon } from "#material-ui/core";
import { PAGES, usePageStatus } from "constants/pages";
const PageItem = ({ page }) => {
const classes = useStyles();
const { label, route, icon } = usePageStatus(page);
return (
<ListItem button component={Link} to={route}>
<ListItemIcon className={classes.icon}>{icon}</ListItemIcon>
<ListItemText primary={label} />
</ListItem>
);
};
const PageList = () => {
const classes = useStyles();
const isMobile = useMediaQuery("(max-width: 600px)", {
noSsr: true,
});
return (
<List className={clsx(isMobile ? classes.mobileList : classes.list)}>
{PAGES.map((page) => (
<PageItem page={page} key={page} />
))}
</List>
);
};
export default PageList;
Here is my code for where I use the PageList component: TopNav.jsx
import React, { useState } from "react";
import clsx from "clsx";
import { makeStyles } from "#material-ui/core/styles";
import useMediaQuery from "#material-ui/core/useMediaQuery";
import {
AppBar,
Toolbar,
Typography,
IconButton,
Drawer,
} from "#material-ui/core";
import MenuIcon from "#material-ui/icons/Menu";
import ChevronRightIcon from "#material-ui/icons/ChevronRight";
import PageList from "./PageList";
import MobileTopMenu from './MobileTopMenu'
const TopNav = () => {
const classes = useStyles();
const isMobile = useMediaQuery("(max-width: 600px)", {
noSsr: true,
});
return (
<AppBar position="static" elevation={0} className={classes.appBar}>
<Toolbar>
<Typography component="a" href="/" className={classes.title}>
Amber+
</Typography>
{isMobile ? <MobileTopMenu /> : <PageList />}
</Toolbar>
</AppBar>
);
};
Here is where I placed my nav bar and my routing code: routes.js
import React from "react";
import { Route, Router, Redirect, Switch } from "react-router-dom";
import { createBrowserHistory } from "history";
import { Home, Missing, Found, Search } from "pages";
import { PAGE_ROUTES, HOME, MISSING, FOUND, SEARCH } from "constants/pages";
import TopNav from "components/common/Nav/TopNav";
const history = createBrowserHistory();
const Routes = () => {
return (
<Router history={history}>
<TopNav />
<Switch>
<Route exact path={PAGE_ROUTES[HOME]} component={Home} />
<Route exact path={PAGE_ROUTES[MISSING]} component={Missing} />
<Route exact path={PAGE_ROUTES[FOUND]} component={Found} />
<Route exact path={PAGE_ROUTES[SEARCH]} component={Search} />
<Route path="*">
<Redirect to={PAGE_ROUTES[HOME]} component={Home} />
</Route>
</Switch>
</Router>
);
};
And this is my code for my page constants: pages.js
export const HOME = "Home";
export const MISSING = "Missing";
export const FOUND = "Found";
export const SEARCH = "Search";
export const PAGES = [HOME, MISSING, FOUND, SEARCH];
export const PAGE_ROUTES = {
[HOME]: "/",
[MISSING]: "/missing",
[FOUND]: "/found",
[SEARCH]: "/search",
};
export const PAGE_ICONS = {
[HOME]: <HomeOutlinedIcon fontSize="small" />,
[MISSING]: <FavoriteBorderIcon fontSize="small" />,
[FOUND]: <ErrorOutlineIcon fontSize="small" />,
[SEARCH]: <SearchIcon fontSize="small" />,
};
export const usePageStatus = (page) => {
const route = PAGE_ROUTES[page];
const icon = PAGE_ICONS[page];
const label = page;
return { route, icon, label };
};
Here is a gif of what I am seeing:
Try this on PageList.jsx
import React, {useCallback} from "react";
import clsx from "clsx";
import { makeStyles } from "#material-ui/core/styles";
import useMediaQuery from "#material-ui/core/useMediaQuery";
import { List, ListItem, ListItemText, ListItemIcon } from "#material-ui/core";
import { PAGES, usePageStatus } from "constants/pages";
import { useHistory } from "react-router-dom";
const PageItem = ({ page }) => {
const classes = useStyles();
const { label, route, icon } = usePageStatus(page);
const history = useHistory();
const goto = useCallback((path) => history.push(path), [history]);
return (
<ListItem button onClick={() => goto(route)}>
<ListItemIcon className={classes.icon}>{icon}</ListItemIcon>
<ListItemText primary={label} />
</ListItem>
);
};
const PageList = () => {
const classes = useStyles();
const isMobile = useMediaQuery("(max-width: 600px)", {
noSsr: true,
});
return (
<List className={clsx(isMobile ? classes.mobileList : classes.list)}>
{PAGES.map((page) => (
<PageItem page={page} key={page} />
))}
</List>
);

How to render all component after an async call?

I'm new to React and I'm currently setup my first project using Gatsby. Essentially I'm creating a website that use an API created with Strapi. So far, I would like to load the navbar items using an API call like that: http://localhost:3001/sections, where for sections, I mean the items of the navbar.
For doing so, I have defined an Index page like that:
import React from "react"
import Layout from "../components/layout/layout"
import SEO from "../components/layout/seo"
import BGTState from "../context/bgt/bgtState"
import "../styles/css/begreentannery.css"
const IndexPage = () => {
return (
<BGTState>
<Layout>
<SEO title="Home" />
</Layout>
</BGTState>
)
}
export default IndexPage
the BGTState contains the getSections() method that is used inside Layout:
import React, { useContext, useEffect } from "react"
import PropTypes from "prop-types"
import { injectIntl } from "gatsby-plugin-intl"
import BGTContext from "../../context/bgt/bgtContext"
import { Spinner } from "react-bootstrap"
import Footer from "./footer"
import SearchState from "../../context/search/SearchState"
import Search from "../../components/search"
import NavbarMobile from "../../components/layout/navbarMobile"
import NavbarDesktop from "../../components/layout/navbarDesktop"
const Layout = ({ children, intl }) => {
const bgtContext = useContext(BGTContext)
const { loading, getSections, sections } = bgtContext
useEffect(() => {
getSections()
//eslint-disable-next-line
}, [])
return !loading ? (
<>
<NavbarMobile sections={sections} />
<NavbarDesktop sections={sections} />
<SearchState>
<Search />
<div className="container-fluid">
<div className="main">
{children}
<Footer />
</div>
</div>
</SearchState>
</>
) : (
<div className="container" style={{ height: "100vh" }}>
<div className="row h-100 justify-content-center align-items-center">
<Spinner animation="grow" />
</div>
</div>
)
}
Layout.propTypes = {
children: PropTypes.node.isRequired,
}
export default injectIntl(Layout)
the problem is in the code above, essentially I call useEffect hook which grab the sections from the API. So, until the sections are downloaded, I stop the code like so:
return !loading ? (
this is the getSections() method inside BGTState:
const getSections = async () => {
try {
setLoading()
const res = await axios.get(
`${process.env.API_URL}/sections?_sort=order:ASC`
)
dispatch({
type: GET_SECTIONS,
payload: res.data,
})
} catch (err) {
dispatch({
type: GET_SECTIONS,
payload: err.response.msg,
})
}
}
in the Index page all works fine, but the problem is in the CollectionsPage, infact I have this structure:
import React from "react"
import { injectIntl } from "gatsby-plugin-intl"
import Layout from "../components/layout/layout"
import SEO from "../components/layout/seo"
import BGTState from "../context/bgt/bgtState"
import CollectionState from "../context/collection/collectionState"
import Collection from "../components/collection"
const CollectionsPage = ({ intl }) => {
return (
<BGTState>
<Layout>
<SEO
lang={intl.locale}
title={`${intl.formatMessage({ id: "collections" })}`}
/>
<CollectionState>
<Collection id={1} />
</CollectionState>
</Layout>
</BGTState>
)
}
export default injectIntl(CollectionsPage)
essentially, the component <CollectionState> isn't mounting 'cause in Layout there is the async call on getSections().
So in Collection component, I have:
import React, { useContext, useEffect } from "react"
import CollectionContext from "../context/collection/collectionContext"
import { Link } from "gatsby"
const Collection = ({ id }) => {
const collectionContext = useContext(CollectionContext)
const { loading, collection, getCollection } = collectionContext
useEffect(() => {
getCollection(id)
}, [])
if (loading) return React.Fragment
return (
<div className="container">
<div className="row">
{/*
<img
src={`${process.env.API_URL}${collection.feature_media.url}`}
className="w-100 mt-2 mb-2"
alt={""}
/>*/}
<Link to="#" className="bg-caption bg-no-underline">
fall/winter 20/21
</Link>
</div>
</div>
)
}
export default Collection
which generate that error:
and of course getCollection is not called and will generate other errors in the Collection component
How can I revisit this mechanism? Essentially I have to:
Load all the sections
Load all the components

React useContext returns default values

I'm trying to create a darkmode library (named react-goodnight) based on https://github.com/luisgserrano/react-dark-mode.
This is where the context is created.
import React from 'react'
const ThemeContext = React.createContext({
theme: '',
toggle: () => {}
})
export default ThemeContext
This is my useDarkMode hook that get/sets the theme to localStorage.
import { useState, useEffect } from 'react'
const useDarkMode = () => {
const [theme, setTheme] = useState('light')
const setMode = (mode) => {
window.localStorage.setItem('theme', mode)
setTheme(mode)
}
const toggle = () => (theme === 'light' ? setMode('dark') : setMode('light'))
useEffect(() => {
const localTheme = window.localStorage.getItem('theme')
localTheme && setTheme(localTheme)
}, [])
return [theme, toggle]
}
export default useDarkMode
This is the index of my library (react-goodnight).
import React, { useContext } from 'react'
import { ThemeProvider } from 'styled-components'
import { GlobalStyles } from './globalStyles'
import { lightTheme, darkTheme } from './settings'
import ThemeContext from './themeContext'
import useDarkMode from './useDarkMode'
const Provider = ({ children }) => {
const [theme, toggle] = useDarkMode()
return (
<ThemeProvider theme={theme === 'light' ? lightTheme : darkTheme}>
<GlobalStyles />
<ThemeContext.Provider value={{ theme, toggle }}>
<button onClick={toggle}>Toggle</button>
{children}
</ThemeContext.Provider>
</ThemeProvider>
)
}
export const useDarkModeContext = () => useContext(ThemeContext)
export default Provider
And, in the end, this is my example app where I'm trying to use it.
import React from 'react'
import Provider, { useDarkModeContext } from 'react-goodnight'
const App = () => {
const { theme, toggle } = useDarkModeContext();
console.log(theme)
return (
<Provider>
<div>hey</div>
<button onClick={toggle}>Toggle</button>
</Provider>
)
}
export default App
The "Toggle" button in the library's index works fine but the one in my example app does not.
The useDarkModeContext() returns empty.
What could be the issue?
Thanks!
You are doing wrong
1st option
you can use react-goodnight provider with your index.js and use useDarkModeContext(), don't name your index.js Provider else you can not use Provider coming from react-goodnight
import Provider, { useDarkModeContext } from 'react-goodnight'
const Provider = ({ children }) => {
const [theme, toggle] = useDarkMode()
return (
<ThemeProvider theme={theme === 'light' ? lightTheme : darkTheme}>
<GlobalStyles />
<Provider>
<ThemeContext.Provider value={{ theme, toggle }}>
<button onClick={toggle}>Toggle</button>
{children}
</ThemeContext.Provider>
</Provider>
</ThemeProvider>
)
}
2nd Option
you are passing ThemeContext in your index.js so you can also access that in app.js
import React, { useContext } from 'react'
import ThemeContext from './themeContext'
const App = () => {
const theme = useContext(ThemeContext);
console.log(theme)
return (
<Provider>
<div>hey</div>
<button onClick={toggle}>Toggle</button>
</Provider>
)
}
export default App
The reason it's not working is because you are calling useContext in the very same place where you print Provider.
Why is that wrong? Because useContext looks for parent context providers. By rendering Provider in the same place you call useContext, there is no parent to look for. The useContext in your example is actually part of App component, who is not a child of Provider.
All you have to do is move the button outside of that print, to its own component, and only there do useContext (or in your case the method called useDarkModeContext.
The only change would be:
import React from 'react'
import Provider, { useDarkModeContext } from 'react-goodnight'
const App = () => {
return (
<Provider>
<div>hey</div>
<ToggleThemeButton />
</Provider>
)
}
export default App
const ToggleThemeButton = () => {
const { theme, toggle } = useDarkModeContext();
return (
<button onClick={toggle}>Switch Theme outside</button>
);
};

Categories

Resources