ReactJs: How to pass api data to components? - javascript

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>
})
))
}
</>
)

Related

Currently unable to display svg images from API in React app

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;

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

how to consume multiple context in reactjs

Is it possible to consume multiple context in one component which is from two different component . I tried It but but I am not getting value
This is the component which consume two different context
import React from "react";
import { UserContext } from "../App";
import { NewContext } from "./CompY";
const CompX = () => {
return (
<div>
<UserContext.Consumer>
{(user) => {
return (
<>
<NewContext.Consumer>
{(username) => {
return (
<>
<h1>Hello {user.username} </h1>
<h2>This is CompX in the {user.name} component</h2>
<h3>This is {username} </h3>
</>
);
}}
</NewContext.Consumer>
</>
);
}}
</UserContext.Consumer>
</div>
);
};
export default CompX;
Here is the App.Js
You can use multiple contexts in functional component easily with useContext
Consumer and provider is bad practice in functional component
import { UserContext } from "../App";
import { NewContext } from "./CompY";
const CompX = () => {
const user = useContext(UserContext);
const newUser = useContext(NewContext);
....
}

React Router: TypeError: render is not a function

Im working on this app and when I run npm start I keep getting this error "TypeError: render is not a function". Ive tired everything from deleting the dependencies to running npm install. I even update react-router-dom and react-dom several times. Im at a lost here.
Here is the GitHub to the repository
https://github.com/Drayz/My-Book-Reads-App.git
Here is the Code:
index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import "./index.css";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
); enter code here
App.js:
import React from 'react'
import { Switch,Route } from 'react-router-dom'
import Homepage from './windows/Homepage'
import Search from './windows/Search'
import Provider, {MyContext} from './Provider/'
import './App.css'
class BooksApp extends React.Component {
render() {
return (
<div className="app">
<Provider>
<MyContext.Consumer>
context
<Switch>
<Route exact path={"/"} render={ () => (
<MyContext.Consumer>
{context => <Homepage {...context} />}
</MyContext.Consumer>
)}/>
<Route exact path={"/search"} render={ () => (
<MyContext.Consumer>
{context => <Search {...context} />}
</MyContext.Consumer>
)}/>
</Switch>
</MyContext.Consumer>
</Provider>
</div>
)
}
}
export default BooksApp
Provider/index.js:
import React, { Component } from 'react';
export const MyContext = React.createContext();
export default class index extends Component {
constructor() {
super();
this.state ={
books:[],
currentlyReading:[],
wantToRead:[],
read:[],
addBooks: books => {
const currentlyReading = books.filter(book => book.shelf === 'currentlyReading');
const read = books.filter(book => book.shelf === 'read');
const wantToRead = books.filter(book => book.shelf ==='wantToRead');
this.setState({ books, currentlyReading, read, wantToRead });
},
moveBook: (book, newShelf, allShelfs) => {
console.log(newShelf);
const newBooks = this.state.books.map(allBooks => {
const foundID = allShelfs[newShelf].find(
bookID => bookID === allBooks.id
);
if (foundID) {
allBooks.shelf = newShelf;
}
return allBooks;
});
this.state.addBooks(newBooks);
}
};
}
render() {
return (
<MyContext.Provider value={{...this.state}}>
{this.props.children}
</MyContext.Provider>
)
}
}
SearchBook.js
import React, {Component} from 'react';
import {Link} from 'react-router-dom'
export default class Searchbooks extends Component {
render() {
return (
<div className="open-search">
<Link to={'/search'}>
Add a book
</Link>
</div>
)
}
}
Bookshelf.js
import React, {Component} from 'react';
import Book from './Book';
export default class Bookshelf extends Component {
render() {
return (
<div className="bookshelf">
<h2 className="bookshelf-title">{this.props.title}</h2>
<div className="bookshelf-books">
<ol className="books-grid">
{this.props.books &&
this.props.books.map(book => <Book key={book.id} {...book} moveBook={this.props.moveBook} />)}
</ol>
</div>
</div>
)
}
}
Book.js
import React, {Component} from "react";
import {update} from '../BooksAPI'
export default class Book extends Component {
handleChange = async e => {
e.presist()
try {
const shelf = e.target.value;
const book = this.props;
const result = await update(book, shelf);
this.props.moveBook(book, shelf, result);
} catch (error) {
console.log(error)
}
};
render() {
return (
<li>
<div className="book">
<div className="book-top">
<div className="book-cover"
style={{
width: 128,
height: 193,
backgroundImage:`url(${this.props.imageLinks ? this.props.imagesLinks.thumnail : ''})`
}}
/>
<div className="book-shelf-changer">
<select onChange={this.handleChange} value={this.props.shelf}>
<option value="move" disabled>Move to...</option>
<option value="currentlyReading">Currently Reading</option>
<option value="wantToRead">Want to Read</option>
<option value="read">Read</option>
<option value="none">None</option>
</select>
</div>
</div>
<div className="book-title">{this.props.title}</div>
<div className="book-authors">{this.props.authors ? this.props.author[0] : 'No Author'}</div>
</div>
</li>
)
}
}
Local_Host_Error, Local_Host_Error, Local_Host_Error
In App.js your consumer just says "context". I think what you meant was for that to be the variable that holds the data that comes from the provider. Right now it's just being read as a string and the render function freaks out because... well the logging isn't very good. In short when the component goes to render it hits a whole bunch of undefined and freaks out.
To fix this use:
{ context => {Your switch statement }}

Export named arrow function got "Object(...) is not a function" error

In a React app I wrote a function in file1.js and use this function in file2.js
// file1.js
export const withPrefix = (Component) => (props) => (
<PrefixContext.Consumer>
{prefix => <Component {...props} prefix={prefix}/>}
</PrefixContext.Consumer>
)
// file2.js
import { withPrefix } from '/path/to/file1.js'
let Toolbar = withPrefix(({prefix}) => ( // !error happens here
<Fragment>
<div style={{flexGrow: 1}}>
<Button><Link to={`${prefix}/create`}>New Artifact</Link></Button>
</div>
<Search style={{width: 200}}/>
</Fragment>
))
Then I got the error "TypeError: Object(...) is not a function". So I changed export withPrefix function
export function withPrefix(Component) {
return (props) => (
<PrefixContext.Consumer>
{prefix => <Component {...props} prefix={prefix}/>}
</PrefixContext.Consumer>
)
}
And the error is gone, everything works. But I wonder why these two exports result differently?
And another question is if I want to export an arrow function in es6, is the 2nd export function style the only method?
Attachment 1 (DefaultView.js):
import React, {Component} from 'react'
import {Layout} from 'antd'
import Toolbar from './Toolbar'
import Content from './Content'
export const PrefixContext = React.createContext()
export function withPrefix(Component) {
return (props) => (
<PrefixContext.Consumer>
{prefix => <Component {...props} prefix={prefix}/>}
</PrefixContext.Consumer>
)
}
export default class DefaultView extends Component {
constructor(props) {
super(props)
this.state = {
view: props.defaultView
}
}
handleViewChange = (view) => {
this.setState({view})
}
render() {
const {prefix, views} = this.props
const {view} = this.state
return (
<PrefixContext.Provider value={prefix}>
<Layout>
<Toolbar view={view} views={views} onViewChange=
{this.handleViewChange}/>
<hr/>
<Content view={view}/>
</Layout>
</PrefixContext.Provider>
)
}
}
Attachment 2 (Summary.js)
import React, {Component, Fragment} from 'react'
import {Button, Input} from 'antd'
import {Link} from 'react-router-dom'
import ArtifactTable from './ArtifactTable'
import {withPrefix} from "./DefaultView"
const {Search} = Input
export const Toolbar = withPrefix(({prefix}) => (
<Fragment>
<div style={{flexGrow: 1}}>
<Button><Link to={`${prefix}/create`}>新建软件包</Link></Button>
</div>
<Search style={{width: 200}}/>
</Fragment>
))
class Summary extends Component {
state = {
data: []
}
componentDidMount() {
const {prefix} = this.props
console.log('prefix=' + prefix)
fetch(prefix).then(json => {
this.setState({data: json.content})
})
}
render() {
const {data} = this.state
return (
<div>
<ArtifactTable data={data}/>
</div>
)
}
}
export default withPrefix(Summary)
Attachment 3 (Toolbar.js)
import React from 'react'
import {Switch, Route} from 'react-router-dom'
import {Toolbar as SummaryToolbar} from './Summary'
import Create from './Create'
import Details from './Details'
import Edit from './Edit'
import {withPrefix} from "./DefaultView"
const Toolbar = withPrefix(({prefix, view, onViewChange}) => (
<div style={{background: '#fff', padding: 16, display: 'flex',
alignItems: 'baseline'}}>
<Switch>
<Route exact path={`${prefix}`} component={SummaryToolbar}/>
<Route exact path={`${prefix}/create`}
component={() => <Create.Toolbar view={view} onViewChange=
{onViewChange}/>}/>
<Route exact path={`${prefix}/:id`}
component={() => <Details.Toolbar view={view} onViewChange=
{onViewChange}/>}/>
<Route exact path={`${prefix}/:id/edit`}
component={() => <Edit.Toolbar view={view} onViewChange=
{onViewChange}/>}/>
</Switch>
</div>
))
export default Toolbar
Update It's indeed the cyclic dependency problem as #Bergi and #loganfsmyth said. After I moved out
the withPrefix export snippet into a new file Context.js from DefaultView.js, the problem resolved. But I still have one quesion. In a cyclic dependency circumstances, why export const f = () => () => {} different from export function f() => { return () => {} }. Is export const lazy evaluated than export function as #loganfsmyth said?

Categories

Resources