How to pass variable between components in react? - html

I have two components, Navbar and ShoppingList. When the user is logged in so I get response from api, I set isLoggedIn variable to true. What I want to do is to show "Logout" button on my navbar when the user is logged in and hide it where he is not. How to pass this value to Navbar component?
ShoppingList fragment
import React, { useState, useEffect } from 'react'
import axiosInstance from '../apis/apiURLS';
function ShoppingList() {
export const [isLoggedIn, setIsLoggedIn] = useState(false);
const getShoppingList = async () => {
await axiosInstance.get('/shoppinglist/')
.then(response => {
if(response){
setIsLoggedIn(true)
setShoppingList(response.data)
}
})
.catch(e => {
console.log(e);
});
}
useEffect(() => {
getShoppingList();
}, [])
Navbar fragment
<div className='navbar'>
<div className='menu-bar-logout' onClick={handleLogout}>
<div class="icon">
</div>
<span>Logout</span>
</div>
</div>

Related

Is it possible to render HTML in a function with React?

I'm new to React, and I'm trying to render html with a function in React.
This is my code:
import React, { Component, useRef, useState, useEffect } from 'react';
import { render } from 'react-dom';
import Searc from './search'
const HandleSearch = () => {
const [name, searchName] = useState("")
const [comments, getComments] = useState([])
const nameForm = useRef(null)
const onSubmitSearch = async(e) => {
e.preventDefault();
try {
// do something
} catch (error) {
console.log(error.message);
}
}
const displayComment = async() => {
try {
const form = nameForm.current
console.log(form['name'].value)
const name = form['name'].value
const response = await fetch(`http://localhost:5000/folder/${name.toLowerCase()}`)
const jsonData = await response.json()
getComments(jsonData)
} catch (error) {
console.log(error.message)
}
}
useEffect(() => {
displayComment()
}, [])
return(
<div className="container">
<div className="form-group">
<h1 className="text-center mt-5">SEARCH MY LANDLORD</h1>
<form ref={nameForm} className="mt-5" onSubmit={onSubmitSearch}>
<Search name={'name'}/>
<div className="d-flex justify-content-center">
<button type="submit" className="d-flex btn btn-primary" onClick={displayComment}>Search</button>
</div>
</form>
<div>
<div>
{/*<tr>
<td>Mary</td>
</tr>*/}
{comments.map(comment => (
<tr>
<td>{comment.problem}</td>
</tr>
))}
</div>
</div>
</div>
</div>
)
}
export default HandleSearch;
The issue I have is that the full list of comments appears before I trigger the displayComments function (once it's trigger it works).
<div>
{/*<tr>
<td>Mary</td>
</tr>*/}
{comments.map(comment => (
<tr>
<td>{comment.problem}</td>
</tr>
))}
</div>
Is it possible to render the above html in the displayComments function so nothing appears before I actually specified which data to display?
You need to remove the useEffect if you want the state to only be set on the button click, because as of right now the state is being set with the useEffect() which is loading when your component is first rendered.

Axios html show value on div

Im trying to put a value that I get from axios on a div while I export that function
import React from 'react';
import axios from 'axios';
function callServer() {
axios.get(`http://localhost:${process.env.REACT_APP_SERVER_PORT}`, {
params: {
table: 'querotable',
},
}).then((response) => {
const resp = response.data;
console.log(resp);
return <div>{JSON.stringify(resp)}</div>;
});
}
export function SampleComponent() {
return (
<div>
{callServer()}
</div>
);
}
It shows nothing on div, only on console with the value that I want
Missing return
Your callServer function doesn't return anything. It doesn't even return a Promise. The statement return <div>{JSON.stringify(resp)}</div> is the return for the .then callback -- not for the function itself.
Use Component State
We could return a Promise that resolves to a div but that wouldn't be right. In order to handle asynchronous data in React we want to store that data to state.
const [resp, setResp] = useState();
Side Effects Go in useEffect
We also need to make sure that the axios.get function is only called once instead of on every re-render of SampleComponent. We can do that with a useEffect hook with an empty dependency array.
export function SampleComponent() {
const [resp, setResp] = useState();
useEffect(() => {
axios
.get(`http://localhost:${process.env.REACT_APP_SERVER_PORT}`, {
params: {
table: "querotable"
}
})
.then((response) => setResp(response.data));
}, []);
return (
<div>
<div>{JSON.stringify(resp)}</div>
</div>
);
}

Extract slug from unsplash

I have a list of photos, fetched from this url https://picsum.photos/v2/list.
In this list there is slug that should be extracted, for example https://unsplash.com/photos/_h7aBovKia4.
Here is fetch thing I used
import React, {Component} from 'react';
import '../App.css';
import ImageList from "./ImageList";
class App extends Component {
constructor() {
super();
this.state = {
images: []
};
}
componentDidMount() {
fetch("https://picsum.photos/v2/list")
.then(res => res.json())
.then(data => {
this.setState({ images: data });
})
.catch(err => {
console.log('Error happened during fetching!', err);
});
}
render() {
return (
<div className="container">
<h2 className="title">Images list</h2>
<ImageList data={this.state.images}/>
</div>
)
}
}
export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.2.0/umd/react-dom.production.min.js"></script>
And here is ImageList Component
import React from "react";
import Image from "./Image";
const ImageList = props => {
const results = props.data;
let images = results.map(image => <Image url={image.url} key={image.id}/>);
return (
<ul className="img-list">{images}</ul>
);
};
export default ImageList;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.0/umd/react-dom.production.min.js"></script>
How can I get that slug from each photo url? without it, images aren't showing in browser, just their alts
UPD. Image Component
import React from "react";
const Image = props => {
return (
<li className="image-wrap">
<img src={props.url} alt="Something went wrong"/>
</li>
)
}
export default Image;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.0/umd/react-dom.production.min.js"></script>
You have to use download_url property, not url.
The url points to a Unsplash page with comments, site interface etc. The download_url however is a direct link to the image.

Understanding React.JS JSON feed and how to parse

I've got the following code which is looping through an JSON file from an API and loops through some posts.
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
//https://alligator.io/react/axios-react/
import axios from 'axios';
export default class PostList extends React.Component {
state = {
posts: []
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
const posts = res.data;
this.setState({ posts });
})
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
Pulls in post slugs from Domain
</p>
<ul>
{ this.state.posts.map(post => <li>{post.name} - {post.username} </li>)}
</ul>
</div>
)
}
}
This works fine, and gets the information which was needed.
Now, in my test JSON file, the format is as follows:
https://jsonplaceholder.typicode.com/users
But in my actual JSON file from WordPress Rest API, we have another item, named core_layout:
JSON image
My issue is, trying to use the same code such as {post.name}does not get the information needed such as core_layout->image->name.
Is there an easy way around this?
Thanks all!
EDIT:
Tried the answers below, but still no luck, get the error TypeError: Cannot read property 'map' of undefined:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
//https://alligator.io/react/axios-react/
import axios from 'axios';
export default class PostList extends React.Component {
state = {
posts: [],
coreLayout: {}
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
// const posts = res.data;
//this.setState({ posts });
const { posts, core_layout: coreLayout } = res.data;
this.setState({ posts, coreLayout });
})
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
Pulls in post slugs from domain
</p>
<ul>
{ this.state.posts.map(post => <li>{post.name} - {post.core_layout.image.name}</li>)}
</ul>
</div>
)
}
}
EDIT 2:
Tried the below: This gets the title, but again, not the actual corelayout I need.
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.state = {
movies: []
}
}
componentDidMount() {
let dataURL = "http://zinsseruk.com/wp-json/wp/v2/posts?per_page=1";
fetch(dataURL)
.then(res => res.json())
.then(res => {
this.setState({
movies: res
})
})
}
render() {
let movies = this.state.movies.map((movie, index) => {
return <div key={index}>
<p><strong>Title:</strong> {movie.title.rendered}</p>
<p><strong>Title:</strong> {movie.core_layout.acf_fc_layout}</p>
</div>
});
return (
<div>
<h2>Star Wars Movies</h2>
{movies}
</div>
)
}
}
export default App;
Replace const posts = res.data; with const posts = res.data.core_layout;. Then you'll get an array similar to what you have in your test file.
I think you need to understand the JSON structure you receive from the API. Where is located core_layout property? Inside each post property as a children?
So in the posts loop you can use post.core_layout.image.name for image name, for example (and so on with other properties).
If core_property is at the root of the data you receive, you can load it inside your state like so:
state = {
posts: [],
coreLayout: {}
}
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
// This is equivalent of doing
// const posts = res.data.posts
// const coreLayout = res.data.core_layout
const { posts, core_layout: coreLayout } = res.data;
this.setState({ posts, coreLayout });
})
}
Then use it in your code by using local component state:
render() {
...
// For example image name:
console.log('image name', this.state.coreLayout.image.name)
...
}

Accessing certain item after fetching data from API with react

I am learning react and stumbled on something that seems like an absolute beginner problem. Anyway I am fetching data from an API and would like to know how to get a certain element from the JSON. I have tried different variations with [] but with no success.
JSON:
[{"name":"gfhf","id":1,"organizer":"hfgh"},{"name":"World Cup","id":2,"organizer":"FIFA"}]
React code:
import React, { Component } from "react";
import Tournaments from "./Tournaments";
const tournyAPI = 'http://localhost:8080/api/tournaments';
class template extends Component {
constructor() {
super();
this.state = {
data: [],
}
}
componentDidMount() {
fetch(tournyAPI)
.then((Response) => Response.json())
.then((findresponse) => {
console.log(findresponse)
this.setState({
data:findresponse,
})
})
}
render() {
return (
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="jumbotron text-center">
{
this.state.data.map((dynamicData, key) =>
<div>
<h1>{dynamicData.name}</h1>
</div>
)
}
</div>
</div>
</div>
</div>
);
}
}
export default template;
My goal would be to display only World cup for example.
You can filter out whatever you want from the response from the API. Like below:
Notice the line findresponse.filter(res => res.name === "World Cup");
componentDidMount() {
fetch(tournyAPI)
.then((Response) => Response.json())
.then((findresponse) => {
console.log(findresponse)
findresponse.filter(res => res.name === "World Cup");
this.setState({
data:findresponse,
})
})
}