Code is here.
What I'm trying to do:
Trying to have the list of movies display, when fetched with Axios, to the area on the right of the app.
I'm not sure if this is a passing prop issue, or if it's something else. Any hints as to what's going on?
import React from "react";
import Card from "#material-ui/core/Card";
import Grid from "#material-ui/core/Grid";
import "../Movie/_movie.scss";
const Movie = props => {
return (
<div>
<Grid container>
<Grid item xs={12} md={12}>
<Card>
<h3>Movies should show up here</h3>
<ul>
{props.movies.map(movie => (
<li key={movie.id}>
<img
src={`https://image.tmdb.org/t/p/w185/${movie.poster_path}`}
/>
<h3>{movie.original_title}</h3>
<p>Date: {movie.release_date}</p>{" "}
<p>Rating: {movie.vote_average}/10</p>
<p>{movie.overview}</p>
</li>
))}
</ul>
</Card>
</Grid>
</Grid>
</div>
);
};
export default Movie;
What's most likely happening is your render function is running before the api call has had time to complete, thus props.movies is undefined at the time when render needs it. What you can do is either give props.movies a default value of
an empty array [] or you can first check to see if props.movies is defined before mapping by doing props.movies && props.movies.map.
While accessing movies object add check props.movies && props.movies.map(movie=>
Related
import React, { useState, useEffect } from 'react';
import { makeStyles } from '#mui/material/styles';
import { Grid, Typography, Link } from '#mui/material';
// We can use the makeStyles hook from MUI to create a custom styles object
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
}));
function App() {
const classes = useStyles();
const [data, setData] = useState(null); // we'll use this state variable to store the data we get from the API
useEffect(() => {
// This function will run when the component mounts (similar to componentDidMount in a class-based component)
// We'll use the fetch API to get data from the API
fetch('https://api.example.com/endpoint')
.then((response) => response.json())
.then((json) => {
setData(json);
});
}, []); // We pass an empty array as the second argument to useEffect to make sure it only runs once
return (
<div className={classes.root}>
<Grid container spacing={3}>
<Grid item xs={12}>
<Typography variant="h2">Hello BeyondMD!</Typography>
</Grid>
<Grid item xs={12}>
{/* Here, we use the Link component from MUI to create a link to a PDF file */}
<Link href="public\Resume+Template.pdf" target="_blank">
View my resume
</Link>
</Grid>
{data && (
<Grid item xs={12}>
{/* If we have data from the API, we can render it here */}
<Typography variant="body1">{data.someProperty}</Typography>
</Grid>
)}
</Grid>
</div>
);
}
export default App;
Im trying to display my resume that I have put in the public and also fetch data from a free API (I dont know where though). In the end it is giving me a blank page with the localhost.
I have tried almost everything I can find online. I want it to display a line of text and my resume and also data from a free API anywhere.
When I am printing the childElement on the console when clicking on the cards it gets displayed correctly
But when I am trying to use CreateRef to scroll to the card on list when the user clicks on that specific card on Google Maps
Yt Tutorial that I am following skipped to the revelant timestamp : https://www.youtube.com/watch?v=UKdQjQX1Pko&t=5274s
Github Link of the code: https://github.com/adrianhajdin/project_travel_advisor
I am using useEffect like this
(in List.jsx)
const [elRefs, setElRefs] = useState([]);
useEffect(()=> {
const refs = Array(places?.length).fill().map((_,i)=> elRefs[i] || createRef());
setElRefs(refs);
},[places]);
Grid Element
<Grid item key={i} xs={12}>
<PlaceDetails
place={place}
selected={Number(childClicked) === i}
refProp={elRefs[i]}
/>
</Grid>
in (PlaceDetails.jsx)
if(selected) refProp?.current?.scrollIntoView({behavior:"smooth", block:"start"})
App.js Code
const [isLoading, setIsLoading] =useState(false);
useEffect(()=>{
setIsLoading(true);
getPlacesData(bounds.sw,bounds.ne)
.then((data)=>{
console.log(data);
setPlaces(data);
setIsLoading(false);
})
},[coordinates,bounds]);
<Grid item xs ={12} md={4}>
<List places ={places}
childClicked={childClicked}
isLoading={isLoading}
/>
Now adding a logical block in List.jsx
{isLoading ? (
<div className={classes.loading}>
<CircularProgress size ="5rem" />
</div>
) :(FormControl Code)}
Here are two warnings i am getting
React Hook useEffect has a missing dependency: 'elRefs'. Either include it or remove the dependency array
Received false for a non-boolean attribute `$hover
I solved the error by setting
const [childClicked ,setChildClicked] =useState();
instead of
const [childClicked ,setChildClicked] =useState(null)
and enclosing the App.js code like
{isLoading ? (
<div className={classes.loading}>
<CircularProgress size ="5rem" />
</div>
) :(<Fragment>FormControl Code</Fragment>)}
instead of
{isLoading ? (
<div className={classes.loading}>
<CircularProgress size ="5rem" />
</div>
) :(FormControl Code)}
I need to pass in an Image object from the page down to a component which calls a component for each image.
Home() -> ThreePanel() -> Panel()
From my understanding of props, this should be possible with the passing of props from ThreePanel to Panel.
But there is an error:
Server Error
Error: Image is missing required "src" property. Make sure you pass "src" in props to the next/image component. Received: {"height":"170em"}
This is what is the source of the error is. I need to specify a specific object. But as a template, I'd like to use a variable.
<Image src={props.cardData.icon} // <-- Doesn't let me specify generic variable
height="170em"/>
<Image src={props.cardData.icon.firstImage}
height="170em"/>
I'm using Next JS.
Here's the full code below:
Home.js
import ThreePanel from '../components/threePanel'
import firstImage from '../public/images/one.png'
import secondImage from '../public/images/two.png'
import thirdImage from '../public/images/three.png'
export default function Home() {
return (
<ThreePanel
panelOne = {{ icon: {firstImage}, name: "First" }}
panelTwo = {{ icon: {secondImage}, content: "Second" }}
panelThree = {{ icon: {thirdImage}, content: "Third" }}>
</ThreePanel>
)
}
threePanel.js
import Panel from '../components/panel'
export default function ThreePanel(props) {
return (
<Grid container>
<Grid item>
<Panel cardData={props.firstImage.icon}></Panel>
</Grid>
<Grid item>
<Panel cardData={props.secondImage.icon}></Panel>
</Grid>
<Grid item>
<Panel cardData={props.thirdImage.icon}></Panel>
</Grid>
</Grid>
)
}
panel.js
import Image from 'next/image'
export default function Panel(props) {
return (
<Image src={props.cardData} // <-- Doesn't let me specify generic variable
height="170em"/>
)
}
Issue
props.firstImage.icon isn't defined in the ThreePanel component as the image was passed as panelOne={{ icon: {firstImage}, name: "First" }}. This means the child component would need to access props.panelOne.icon.firstImage to get to the image. This may work if each Panel component is passed the correctly nested property.
<Panel cardData={props.panelOne.icon.firstImage} />
<Panel cardData={props.panelTwo.icon.secondImage} />
...etc...
As you can see, each child panel needs to know which panel it is, but also needs to know what the image property was named. This isn't ideal.
Solution
You should strive to pass consistently named props down to "repeated" children as each "instance" won't be aware which dynamic prop they should access. In this case it's the value passed that is dynamic, not the prop key.
Home
Pass the dynamic image values on a standard prop, like icon.
import firstImage from '../public/images/one.png';
import secondImage from '../public/images/two.png';
import thirdImage from '../public/images/three.png';
export default function Home() {
return (
<ThreePanel
panelOne={{ icon: firstImage, name: "First" }}
panelTwo={{ icon: secondImage, content: "Second" }}
panelThree={{ icon: thirdImage, content: "Third" }}
/>
)
}
ThreePanel
Access the "dynamic" panel prop to pass the specific panel prop object to each Panel component. Now the intermediate ThreePanel component doesn't need to know much of the deeper nested values, it knows to pass 1 of 3 panel prop objects to it's 3 panel children.
export default function ThreePanel(props) {
return (
<Grid container>
<Grid item>
<Panel cardData={props.panelOne} />
</Grid>
<Grid item>
<Panel cardData={props.panelTwo} />
</Grid>
<Grid item>
<Panel cardData={props.panelThree} />
</Grid>
</Grid>
)
}
Panel
Now the passed carData prop will be the specific image that was passed from grandparent/ancestor component. Notice here that each individual panel doesn't know which of the 3 panels it is, but it knows it has an image icon prop to access.
export default function Panel(props) {
return (
<Image
src={props.cardData.icon}
height="170em"
/>
)
}
In threePanel.js the panel props should be cardData=props.panelOne, isnt it? Instead of props.cardOne
Experts am in the learning stage and I wanted to know how can I can get the text input value from the search bar and pass it to my another component where I have an API URL as a search query.
I have seen many videos which use props and I guess that’s the correct way if not wrong to send the data between components. However, I tried to use that but I have an issue. I can not see the props value which I have passed from my nav component (textfiled value) to the product component.
any help how can I do that.
Please if you can provide a source code explanation would be great.
Also please find the relevant code below:
Please see the full code here https://codesandbox.io/s/determined-nightingale-m2mtn?file=/src/App.js
This is the code on my nav component and I want the onchange value to be passed to the product component.
const Navbar = () =>{
const[searchText, setSearchText] = useState();
const handleChange = (event) =>{
setSearchText(event.target.value)
}
return (
<>
<div className="nav_main">
<div className="logo_main">
<Link exact to='/home' className="logo" > Movie </Link>
</div>
<div className="search_main">
<TextField
id="input-with-icon-textfield"
className= "searchTextStyle"
size= "small"
placeholder="search"
variant="standard"
value = {searchText}
onChange = {handleChange}
InputProps={{
startAdornment: (
<InputAdornment position="start">
<SearchIcon style={{color:'white'}} />
</InputAdornment>
),
}}
/>
</div>
<div className="nav_menu">
<NavLink exact activeClassName= "active_link" to='/home' className="navitems" > Home </NavLink>
<NavLink exact activeClassName= "active_link" to='/about'className="navitems" > About </NavLink>
<NavLink exact activeClassName= "active_link" to = '/products' className="navitems" > Products </NavLink>
<IconButton className="account_icon">
<AccountCircleIcon fontSize="small"/>
</IconButton>
</div>
</div>
</>
)
};
export default Navbar;
The Product component:
const Produts = (props) =>{
console.log(props.value);
return (
<>
<h1>{`http://api.themoviedb.org/3/search/movie?api_key=Mykey&query=${props.value}`}</h1>
</>
)
};
export default Produts;
Thanks
how are you?
What happens is, it's okay, you are getting the data from de input, but you are not passing it forward to the other component where you want to use that data.
How can you do that?
As they are 'sibling' components, i recommend you to put the handleChange and the useState where you are going to save the data in the FATHER component, pass them through props for the component where the user types, and then pass the stored data also via props for the component where you are going to use it.
Let me give you a pratical example of how you can do it:
On the App you handle the state and provide it for the components via props.
function App() {
const [searchText, setSearchText] = useState();
const handleChange = (event) => {
setSearchText(event.target.value);
};
return (
<>
<Navbar handleChange={handleChange} searchText={searchText}/>
<Switch>
<Route path="/products"
render= { (props) => <Produts {...props} searchText={searchText} /> }
/>
</Switch>
</>
);
}
in the NavBar component you get them via props, destructuring it:
const Navbar = ({handleChange, searchText}) => {
return (
<>
<div className="nav_main">
<div className="logo_main">
<Link exact to="/home" className="logo">
{" "}
Movie{" "}
</Link>
</div>
and in the Produts component you get them also via props:
const Produts = (props) => {
console.log(props.searchText);
const classes = useStyles();
const [movieData, setMovieData] = useState([
// the below is an fake api data which needs to be deleted when final disgn is ready and add real api from useEffect
{
adult: false,
observe that, before you were getting "props.value" but the name that you get in the component is the same name that you used to pass it from the provider component, in this case 'searchText'.
tl;dr
You need to pass them via props, choosing a name, and you get them from the other side using the same name. To get them you can either use 'props.PROP_NAME' or you can use the destructuring method and get the name directly.
Also, to pass a props through a Router rendered component you have to use this syntax:
render= { (props) => <Produts {...props} PROP_NAME={VARIABLE_YOU_ARE_USING}
On the NavBar and the Produts components i used different methods so you can see that you can use both for getting the props information.
I hope that can help, anyway i'm available for further explanations.
The NavLink has additional properties which can be used. The 'to' attribute needn't be only a string value. For example:
<NavLink exact activeClassName= "active_link" to = '/products' className="navitems" > Products </NavLink>
can be rewritten as
to={{
pathName: '/products',
someProps:{data: 'Place any Data here'}
}}
className="navitems" > Products </NavLink>
Then in your products component you should be able to retrieve the data using this.props.location.someProps.data.
Take a look at these articles:
https://reactrouter.com/web/api/Link/to-object,
https://medium.com/#bopaiahmd.mca/how-to-pass-props-using-link-and-navlink-in-react-router-v4-75dc1d9507b4
They outline exactly how this should be used.
I'm aware that this error may be quite common and have been answered several times before, but I couldn't find a solution.
My code always throws this error: ".map is not a function". I know that this happens because data is not an array. So I tried to solve this with .keys function but this throws the ".keys is not a function" error. I'm declaring const data in the parent component and want to use it in the child component.
I think my error depends on a false use of .keys. But after much Googling I'm still not one step further.
This is my Child-Code:
import React from "react";
import Card from 'react-bootstrap/Card';
import Col from 'react-bootstrap/Col';
import Row from 'react-bootstrap/Row';
import Container from 'react-bootstrap/Container';
import {Link} from 'react-router-dom'
const PostsRow = (data) => {
{return (
<Container>
<Row>
{data.keys(data).map((data) => {
console.log(data + "is mount")
return (
<Col className="col-6 col-md-6 col-lg-3 card">
<Link to={data.url}>
<Card className=" text-center ">
<Card.Img variant="top" src={data.imagesrc} />
<Card.Body>
<Card.Title>{data.title}</Card.Title>
</Card.Body>
</Card>
</Link>
</Col>
);
})}
</Row>
</Container>
);
};
export default PostsRow;
This is home.jsx (parent):
import React from "react";
import './route.css';
import PostsRow from "../components/Content/PostsRow";
const Home = () => {
const data = {
title: "Ersti",
imagesrc: "./490.jpg",
url: "/meineposts"
};
return (
<div>
<PostsRow data={data}/>
</div>
);
};
export default Home;
This is working fine as long as const data is declared in the PostsRow.jsx, but when I try to declare it in Home.jsx and use props the above error throws.
As data is an object. To get its keys, you should write: Object.keys(data).
And, you have a typo in props destructuring : it should be ({data}).
Your example data is simply an object, not an array, so you don't need to use map or Object.keys here, you can simply write:
<Col className="col-6 col-md-6 col-lg-3 card">
<Link to={data.url}>
<Card className="text-center">
<Card.Img variant="top" src={data.imagesrc} />
<Card.Body>
<Card.Title>{data.title}</Card.Title>
</Card.Body>
</Card>
</Link>
</Col>
PostsRow will be called with props and data is property of it. so you have to use it like
const PostsRow = ({data}) => {
And you've to convert your data to array like
const data = [{
title: "Ersti",
imagesrc: "./490.jpg",
url: "/meineposts"
}];