I can't seem to solve this, The URLs are not showing as images, what can I do?
I think the issue is with the style background image but I'm not sure, the name is showing fine but the image is not.
here is the code:
import React, {useState} from "react";
import TinderCard from "react-tinder-card";
function TinderCards() {
const [people, setPeople] = useState([
{
name:"sonny",
url:"https://upload.wikimedia.org/wikipedia/commons/b/b8/Lola_Astanova.jpg",
},
{
name:"danny",
url:"https://upload.wikimedia.org/wikipedia/commons/b/b8/Lola_Astanova.jpg",
},
]);
// const people = []; array
return (
<div>
<h1>cards</h1>
{people.map((person) => ( <TinderCard
className="swipe"
key={person.name}
preventSwipe={['up', 'down']}
>
<div
// eslint-disable-next-line no-template-curly-in-string
style={{ backgroundImage: 'url(${person.url})' }}
className="card">
<h3>{person.name}</h3>
</div>
</TinderCard>
))}
</div>
);
}
export default TinderCards
That's what I would do as well. Work backwards if stuck. I would think the tics would work. Not showing image equates to? Have you viewed source / what was output?
Related
In my app I want to make my element always scrolled to bottom after getting new logs.
For some reason my logsRef.current.scrollTop has value of zero all the time. My logs do show on screen and in console. I am not sure why is this not working, I've tried to use different approaches using useLyaoutEffect() but nothing made logsRef.current.scrollTop value change, it stayed zero all the time.
//my Logs.jsx component
import { useEffect, useRef } from "react";
import Container from "./UI/Container";
import styles from "./Logs.module.css";
const Logs = ({ logs }) => {
const logsRef = useRef(null);
useEffect(() => {
logsRef.current.scrollTop = logsRef.current.scrollHeight;
console.log(logs);
console.log(logsRef.current.scrollTop);
}, [logs]);
return (
<Container className={`${styles.logs} ${styles.container}`}>
<div ref={logsRef}>
{" "}
{logs.map((log, index) => (
<p key={index}>{log}</p>
))}
</div>
</Container>
);
};
export default Logs;
Also, I do render my Logs.jsx in BattlePhase.jsx component where I do my attack logic on click and I save logs using useState() hook.
//parts where i do save my logs in BattlePhase.jsx
const [logs, setLogs] = useState([]);
const attackHandler = () => {
//logs where pokemon on left attacked pokemon on right
setLogs((prevLogs) => [
...prevLogs,
`${pokemonDataOne.name} attacked ${
pokemonDataTwo.name
} for ${attack.toFixed(2)} dmg`,
`${pokemonDataTwo.name} died`,
])
}
...
<Attack className={isActiveArrow}>
<Button onClick={attackHandler}>Attack!</Button>
</Attack>
Slight long shot but it's possible that the ref is attached to the wrong element. Are you sure the element with the CSS property that makes it scrollable (overflow) isn't on <Container>?
//my Logs.jsx component
import { useLayoutEffect, useRef } from "react";
import Container from "./UI/Container";
import styles from "./Logs.module.css";
const Logs = ({ logs }) => {
const logsRef = useRef(null);
useLayoutEffect(() => {
logsRef.current.scrollTop = logsRef.current.scrollHeight;
console.log(logs);
console.log(logsRef.current.scrollTop);
}, [logs]);
return (
<Container className={`${styles.logs} ${styles.container}`} ref={logsRef}>
<div>
{" "}
{logs.map((log, index) => (
<p key={index}>{log}</p>
))}
</div>
</Container>
);
};
export default Logs;
Also to confirm, you do need useLayoutEffect here.
I'm following this tutorial on YouTube https://youtu.be/b9eMGE7QtTk
The full code can be found here: https://gist.github.com/adrianhajdin/997a8cdf94234e889fa47be89a4759f1
The tutorial was great, but it didn't split all the functionalities into components which is React used for (or I'm so lead to believe).
So we have the App.js
import React, { useState, useEffect } from "react";
import MovieCard from "./MovieCard";
import SearchIcon from "./search.svg";
import "./App.css";
const API_URL = "http://www.omdbapi.com?apikey=b6003d8a";
const App = () => {
const [searchTerm, setSearchTerm] = useState("");
const [movies, setMovies] = useState([]);
useEffect(() => {
searchMovies("Batman");
}, []);
const searchMovies = async (title) => {
const response = await fetch(`${API_URL}&s=${title}`);
const data = await response.json();
setMovies(data.Search);
};
return (
<div className="app">
<h1>MovieLand</h1>
<div className="search">
<input
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Search for movies"
/>
<img
src={SearchIcon}
alt="search"
onClick={() => searchMovies(searchTerm)}
/>
</div>
{movies?.length > 0 ? (
<div className="container">
{movies.map((movie) => (
<MovieCard movie={movie} />
))}
</div>
) : (
<div className="empty">
<h2>No movies found</h2>
</div>
)}
</div>
);
};
export default App;
MovieCards.jsx is as follows:
import React from 'react';
const MovieCard = ({ movie: { imdbID, Year, Poster, Title, Type } }) => {
return (
<div className="movie" key={imdbID}>
<div>
<p>{Year}</p>
</div>
<div>
<img src={Poster !== "N/A" ? Poster : "https://via.placeholder.com/400"} alt={Title} />
</div>
<div>
<span>{Type}</span>
<h3>{Title}</h3>
</div>
</div>
);
}
export default MovieCard;
The app works, but I want to move className="search" to be its own component like Search /.
The code I end up having in App.js is
//at the top of App.jx
import Search from "./Search"
// in const App
<Search prop={searchMovies}/>
And in the new Seach / component
import { useState } from "react";
import SearchIcon from './search.svg';
const Search = ( prop ) => {
const [searchTerm, setSearchTerm] = useState("");
return (
<div className="search">
<input
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Search"
/>
<img
src={SearchIcon}
alt="search"
onClick={() => prop(searchTerm)}
//props used to be searchMovies
/>
</div>
)
}
export default Search;
When typing something in the search field on the app and clicking on the search icon I get the following error:
prop is not a function
If my research has been correct, I need to use a constructor and super()
But it seems like the constructor needs to be called in a class Search instead of const Search as it breaks the code. Is that the case or is there a way to use the constructor in a function component, or is there something else completely that I should do?
Also, if there is a great tutorial you could recommend for super() I'd be really grateful.
Other thing that I want to do is to make a Results component or call it whatever that would have the {movies?.length > 0 ? ( part of the code, but I feel like that will be a different headache.
Basically what I want is to have:
const App = () => {
return (
<div className="app">
<h1>Movie Site</h1>
<Search />
<Results />
</div>
);
};
Or as shown in the picture
Hope all this makes sense. Also, I want to preface that I do not expect anyone to write the code for me, but if it helps me understand this it's appreciated. YT tutorials are appreciated as well.
Okay, after a push in the right direction from jonrsharpe and renaming the props into random things I figured it out.
As jonrsharpe said, my function is prop.prop, so if I wanted to call searchTerm in
onClick={() => prop(searchTerm)}
it should be
onClick={() => prop.prop(searchTerm)}
Now, that works, but looks silly. So renaming the first "prop" in prop.prop and the prop in const Search to searchOnClick leaves searchOnClick.prop(searchTerm) which still works. Great.
Then in App.js renaming prop in Search prop={searchMovies} to searchOnClick={searchMovies} needs to be followed by renaming searchOnClick.prop in Search.jsx to searchOnClick.searchOnClick.
Lastly, we want to destructure the props as jonrsharpe said.
const Search = ( searchOnClick ) => {
would become
const Search = ( {searchOnClick} ) => {
That allows us to remake searchOnClick.searchOnClick(searchTerm) to searchOnClick(searchTerm) only.
The whole point is that the prop calls the whole componentName variable=value but it doesn't take the value of the variable automatically so it needs to be called like prop.variable until destructured where it can be called as variable only.
Now that I figured this out it feels silly spending two days on this. Thanks to jonrsharpe again, and hope this helps to someone else in the future.
So I'm pretty much new in React/Web development and just can't figure it out regarding ReactPlayer.
I have a .JSON file with [ID, Question, URL] and I load the questions into divs. What I want is when I click the div(question) then the URL that is assigned to that question should load in the ReactPlayer..
This is how it looks so far:
import React, { useState } from "react";
import Questions from "../data/questions.json";
import style from "./Card.module.css";
import ReactPlayer from "react-player/youtube";
function Card() {
const handleClick = (item) => {
console.log(item);
};
return (
<div>
<div className={style.ViewContent}>
<div className={style.mainCard}>
{ListQuestions.map((ListItem, index) => {
return (
<div onClick={() => handleClick(ListItem.url)} key={index} className={style.Card}>
<h3 className={style.Titel}>{ListItem.question}</h3>
</div>
);
})}
</div>
<div className={style.VideoPlayer}>
<ReactPlayer url={handleClick.item} controls={true} />
</div>
</div>
</div>
);
}
export default Card;
I tested the click function and every time I click the question the console logs only the URL.
But how can the ReactPlayer get that URL and play the video?
I'm sorry for the bad coding.. still learning :)
I tried adding onSubmit on the div box so when clicking the div it should submit/load the link to the ReactPlayer... but thinking logically and then interpreting it kind of does not work.
I figured it out :D
import React, { useState } from "react";
import Questions from "../data/questions.json";
import style from "./Card.module.css";
import ReactPlayer from "react-player";
function Card() {
const [playUrl, setPlayUrl] = useState(""); ← here you could put the youtube link to show up when loading the page.
const [isPlaying, setIsPlaying] = useState(true);
return (
<div>
<div className={style.ViewContent}>
<div className={style.mainCard}>
{ListQuestions.map((ListItem, index) => {
return (
<div onClick={() => setPlayUrl(ListItem.url)} key={index} className={style.Card}>
<h3 className={style.Titel}>{ListItem.question}</h3>
</div>
);
})}
</div>
<div className={style.VideoPlayer}>
<ReactPlayer url={playUrl} controls={true} playing={isPlaying} />
</div>
</div>
</div>
);
}
export default Card;
I'm making a simple react app to take trivia questions and answers from an api and display them as a game.
My development of this app has been running smoothly and updating as per expected, however when I imported a decode function to make the trivia questions present correctly, I noticed that further edits of the code would result in a blank white screen, after commenting out some code I've managed to isolate what code seems to be causing the issue.
App.js
import React from 'react'
import Questions from './Questions'
import { nanoid } from 'nanoid'
import { decode } from 'he'
function App() {
const [tempState, setTempState] = React.useState(false)
const [data, setData] = React.useState({})
React.useEffect(() => {
fetch("https://opentdb.com/api.php?amount=5&category=9&difficulty=medium")
.then(res => res.json())
.then(info => setData(info.results.map(item => {
return {
type: item.type,
question: item.question,
correct_answer: item.correct_answer,
incorrect_answers: item.incorrect_answers,
id: nanoid()
}})))
}, [])
const questionElements = data.map(item => (
<Questions
key={item.id}
type={item.type}
question={item.question}
correct_answer={item.correct_answer}
incorrect_answers={item.incorrect_answers}
/>
))
return (
<main>
<img className="blob--top"
src={require('./blobs.png')}
/>
<img className="blob--bottom"
src={require('./blobs1.png')}
/>
{tempState ?
<div className="quiz--container">
<div>
{questionElements}
</div>
</div> :
<>
<div className="title--container">
<div className="title--init">
<h2 className="title--header">Quizzical</h2>
<h4 className="title--subheader">A battle of the brains</h4>
<button className="game--start"
onClick={() => setTempState(!tempState)}
>
Start quiz</button>
</div>
</div>
</>
}
</main>
);
}
export default App;
Questions.js
import React from 'react'
import { decode } from 'he'
export default function Questions(props) {
return(
<div className="question--container">
<h4>{decode(props.question)}</h4>
<div className="question--items">
<button>{decode(props.correct_answer)}</button>
<button>{decode(props.incorrect_answers[0])}</button>
<button>{decode(props.incorrect_answers[1])}</button>
<button>{decode(props.incorrect_answers[2])}</button>
</div>
</div>
)
}
commenting out the following two code sections in App.js resolves the error
const questionElements = data.map(item => (
<Questions
key={item.id}
type={item.type}
question={item.question}
correct_answer={item.correct_answer}
incorrect_answers={item.incorrect_answers}
/>
))
<div>
{questionElements}
</div>
any ideas on what I'm doing wrong? no error messages show up in react, it just shows a blank white screen.
The blank white screen is caused by the error data.map is not a function, which is caused by your setting default value of the data state to be an empty object while it should be an empty array (so that you can map through).
To fix this error, simply set the default value of data to be an empty array.
const [data, setData] = React.useState([])
Code Sandbox: https://codesandbox.io/embed/inspiring-rhodes-gp5kki?fontsize=14&hidenavigation=1&theme=dark
I am getting this error while using useRef and useEffect in react js.
**how can i cleanup the useEffect in React js this is main topic of this all question **
Dropdown.js:9
Uncaught TypeError: Cannot read properties of null (reading 'contains')
at HTMLDocument.bodydroptoggler (Dropdown.js:9)
here is screenshot:
I am getting this error when i click on the button named as "drop toggler"
here is code of app.js
import React, { useState } from "react";
import Dropdown from "./components/Dropdown";
const options = [
{
label: "red color is selected",
value: "red",
},
{
label: "blue color is selected",
value: "blue",
},
{
label: "green color is seleted",
value: "green",
},
];
const App = () => {
const [dropactive, setDropactive] = useState(true);
return (
<div className="container ui">
<button
className="button ui"
onClick={() => setDropactive(!dropactive)}
>
drop toggler
</button>
{dropactive ? <Dropdown options={options} /> : null}
</div>
);
};
export default App;
and here is code of dropdown.js
import React, { useState, useRef, useEffect } from "react";
const Dropdown = ({ options }) => {
const [selected, setSelected] = useState(options[0]);
const [open, setOpen] = useState(false);
const ref = useRef();
useEffect(() => {
const bodydroptoggler = (event) => {
if (ref.current.contains(event.target)) {
return;
}
setOpen(false);
};
document.addEventListener("click", bodydroptoggler);
return () => {
document.removeEventListener("click", bodydroptoggler);
console.log("work");
};
}, []);
const RenderedOptions = options.map((option, index) => {
if (selected.value === option.value) {
return null;
} else {
return (
<div
className="item"
key={index}
onClick={() => {
setSelected(option);
}}
>
{option.label}
</div>
);
}
});
return (
<div ref={ref} className="ui form">
<div className="field">
<label className="text label">Select from here:</label>
<div
className={`ui selection dropdown ${
open ? "active visible" : ""
}`}
onClick={() => setOpen(!open)}
>
<i className="dropdown icon"></i>
<div className="text">{selected.label}</div>
<div className={`menu ${open ? "visible transition" : ""}`}>
{RenderedOptions}
</div>
</div>
</div>
</div>
);
};
export default Dropdown;
here is what i want to perform
i just want to hide that form by clicking on the button.
how you can run this project
just create a react app
put code of app.js to app.js of your project
dropdown.js inside the component folder
i hope this all detail will help you i you need anything more just commnet down
thanks in advance
Have you tried using optional chaining since ref.current might sometimes be undefined?
if (ref.current?.contains(event.target))
Here's a codesandbox link with the fix.
Also some additional context from React Ref docs on why sometimes the ref might be null
React will assign the current property with the DOM element when the component mounts, and assign it back to null when it unmounts.
EDIT:
This is whay useLayoutEffect is for. It runs it's contents (and cleanups) synchronously and avoids the race condition. Here's the stackblitz that proves it:
https://stackblitz.com/edit/react-5w7vog
Check out this post from Kent Dodd's as well:
One other situation you might want to use useLayoutEffect instead of useEffect is if you're updating a value (like a ref) and you want to make sure it's up-to-date before any other code runs. For example:
ORIGINAL ANSWER
It's complicated. Your code generally looks good so it took me a minute to understand why. But here's the why - the Dropdown component unmounts before the cleanup from the effect is run. So the click event still finds the handler, this time with a null reference for the ref (because the ref gets updated immediately).
Your code is correct, idomatic React - but this is an edge case that needs deeper understanding.
As the other answerer already mentioned, just add an optional check. But I thought you might like to know why.