How to show a random element of an json object from localhost? - json

I wish to show a random quote from a local database every time I reload the page. I'm fetching the data from localhost:3000 using custom useFetch hook but all I've ever did was map trough the entire object and show every element; now I only need to show one element and make it random. This is my attempt:
const Header = () => {
const { data } = useFetch('http://localhost:3000/Quotes')
const quotes = data.map(quote => ({ quote }))
const quote = quotes[Math.floor(Math.random() * quotes.length)]
return (
<div className='header'>
<div className='quothe'>
<h2 key={quote.id}>{quote.title}</h2>
<h3 key={quote.id}>- {quote.author}</h3>
</div>
</div>
)
}

Related

Conditionally make a page read-only using react

I want to create a React webpage that has both editable and read-only versions, the whole page not just a few elements on the page. A version is displayed to the user based on user id and other conditions. How do I do it?
The only straight forward way I know is to create 2 pages one editable and one read-only and based on the condition show the appropriate version (html page) to the user.
Is there a better and smarter way to do this? Like can I create just one page for both versions and toggle the mode based on the condition to the users?
Your question should have provided an example of some code you had tried but based on the description, very rough example below of one of many possible solutions.
Suppose EditView component is your page and you are able to pass a value for permission based on whatever credential you need to apply.
Then you have a component, ExampleField that takes the permission and displays either an input or static text. A collection of multiple of these fields is mapped from a theoretical array of data that you'll have to fetch from somewhere and the fields are returned by the main component.
const EditView = ({permission}) => {
const [editable, setEditable] = useState();
const [values, setValues] = useState([]);
useEffect(() => {
setEditable(permission);
}, [permission]);
useEffect(() => {
//maybe fetch your data from a back end or whatever and assign it to `values`
//on page load
}, [])
const ExampleField = ({permission, val, index}) => {
const handleChange = (e) => {
let vals = [...values];
vals[index] = val;
setValues(vals);
}
return(
<>
{permission
? <input name="example" type="text" defaultValue={val}
onChange={handleChange} />
: <span>{val}</span>}
</>
)
}
const fields = values.map((value, i) => {
return <ExampleField permission={permission} val={value} index={i}/>
})
return(
<>
{fields}
</>
)
}
Most likely, you'll want to break out various field components into their own file and, instead of using useState, you would probably want to explore useContext or useStore type functionality to lift up your state and do all the react things.
*Haven't tested or even compiled this code - for illustration purposes only.

I am displaying dynamic data on this React Boostrap Slider. Is there a way to make the code more efficient?

this is my first post here. I am building a React Boostrap Carousel that pulls Movie data from the database and displays it. I am new to React and programming in general. So far i made the code work. But i do not know how to handle the images. The images are stores in React **src/assets/imgs. **. Should i store a reference to the image in the database like so ../../assets/imgs/the-batman.jpg and then display it? If so later on on the project the admin will have to create a MovieOfTheMonth. He should be able to input movie title, descrition etc, and also upload a movie image. Is there a way when the image is uploaded it, to store it to a specific folder, in this case src/assets/imgs and also create a reference in the database? I do not need the solution here, just to tell me if it is achievable. Finally is there a way to improve my code?
this is my full code for this component
import React, {useState, useEffect } from 'react';
import './Carousel.css'
import Carousel from 'react-bootstrap/Carousel';
import 'bootstrap/dist/css/bootstrap.min.css';
import axios from 'axios';
const CarouselHero = () => {
//boostrap code
const [index, setIndex] = useState(0);
const handleSelect = (selectedIndex, e) => {
setIndex(selectedIndex);
};
//Get Movies of the month
const [movie, setMovie] = useState([])
const getMovie = () => {
axios.get("http://localhost:4000/moviesOfTheMonth")
.then((res) => {
const myMovie = res.data
myMovie.push()
setMovie(myMovie);
})
}
useEffect(() => getMovie(), []);
return (
<Carousel activeIndex={index} onSelect={handleSelect} fade>
{movie.map((item) => {
const {id, title, description} = item.Movie
return (
<Carousel.Item interval={2000}>
<img
src={require("../../assets/imgs/the-batman.jpg")}
alt="First slide"
/>
<Carousel.Caption >
<h1>{title}</h1>
<p>{description}</p>
<button>Book Now</button>
</Carousel.Caption>
</Carousel.Item>
)
})}
</Carousel>
);
};
export default CarouselHero;
I think technically it is achievable to iterate over the assets folder and create database entries for new images (create and compare hash?), but it is usually not how you do it. I would put images in some file storage like S3 and reference them with id.
I don't know who the admin will be in your project, but if admin is rather a non technical person, you could create (or use a template of course) a small and simple admin dashboard, where he/she can maintain a movie of the month via UI.
FFinally some remarks on your code:
const handleSelect = (selectedIndex, e) => { setIndex(selectedIndex); }; - If you need only first, but not second, third etc. argument, you can just leave it out: (selectedIndex) => ...
const [movie, setMovie] = useState([]) - don't forget to use semicolon after every statement. (They are optional, but are useful sometimes to avoid weird errors). Also, you have a list here. So maybe better call it "movies".
myMovie.push() - What are you trying to push here?
useEffect(() => getMovie(), []); - Usually you define and call async function directly in useEffect. Don't you get any hints or warning?
movie.map((item) => { - When you iterate and get a list back React needs a key on every element (here on Carousel.Item). Don't just use the index, as it is a bad practice. Always try to find id property in your data.
const {id, title, description} = item.Movie - Why is the data nested by Movie object? Can't you just say item.id, item.title, item.description?

How is data handled with getStaticProps when component uses it in useEffect()?

I have a page that uses the getStaticProps function. The function loads a list of objects that each hold three things: the title of a book, the author of a book, and then a list of characters in the book. The page then maps each of these objects to a component that puts them in a pretty pill.
The component takes the title and author and embeds it into its HTML code. However, the one complexity is the component also uses a useEffect() hook to randomly select 1 character within the character list provided as a prop and then displays them as part of the component HTML. Since it is useEffect(), this does not happen at build time. The reason I want it to occur when the user requests the page is that each user should see a different randomly selected character (i.e., although everything else on the page is the same for all users, I want the character to be randomly selected).
My question is, can getStaticProps work here? Does it build out the HTML as best it can and then when the user requests the page, the character list data is already provided? Or because it uses useEffect(), the component will have to re-request the data from the backend? I want to limit backend requests because the data is stored in AirTable and that only allows 5 calls per second.
index.jsx:
const Home = (props) => {
return (
<div className="flex min-h-screen">
<main className="relative mx-5 mt-16">
{props.response.map((bookData) => (
<BookPill
bookTitle={bookData['Book Title']}
bookAuthor={bookData['Book Author']}
bookCharacters={bookData['Characters']}
/>
))}
</main>
</div>
)
}
export default Home
export async function getStaticProps(context) {
try {
const response = await getBookData()
return {
props: {
response,
},
revalidate: 5,
}
} catch (error) {
return {
props: {
err: 'Something went wrong 😕',
},
}
}
}
BookPill.jsx:
const BookPill = ({
bookTitle,
bookAuthor,
bookCharacters,
}: PropsType) => {
const [randomCharacter, setRandomCharacter] = useState('')
useEffect(() => {
const random_character =
bookCharacters[Math.floor(Math.random() * bookCharacters.length)]
setRandomCharacter(random_character)
}, [])
return (
<div className="my-2 grid grid-cols-1">
<div className="px-5 text-center">
<p className="mb-4">{bookTitle}</p>
<p className="text-sm">{bookAuthor}</p>
</div>
<div className="flex items-center justify-center md:col-span-1">
<div className="rounded-3xl">
{randomCharacter}
</div>
</div>
</div>
)
}
export default BookPill
To summarize what was discussed in the comments:
Because you're using getStaticProps with revalidate: 5, the data will only be fetched on the server, at most every 5 seconds. The data fetched inside getStaticProps is then passed to the HTML generated for the page - you can see the props returned from getStaticProps in the __NEXT_DATA__ script in your HTML.
When the page gets rendered on the browser, the useEffect is triggered and will use that data. No additional requests occur on the client-side.

How to create a string map "location" and "location Value Text" of this string text?

I developed project using anguler with ngRx framework. I used TypeScript with HTML for developing front-end.My db have saved 'HTML' format texts like below.
"<html><body>A.txt
B.txt
D.txt
www.facebook.com
</body></html>"
This text priviouly , I drectly render in html file using <dev INNERHTML ={{stringText }} \> like wise.
But my project using JXBrowser and as it's configuration , this can't be directly open in default browser clicking just link.
For that work ,I need to take href location as URL and when click it passed to .ts file.
I thought ,it change as like this <a role="button" click='getLink(myText)'> {{getLink(value}} </a>'. so ,create this ,I need that text put a array with contain 'location' and value.Next ,I though ,Iterate that array in HTML file.
I need some expert help to do this ? I am struggle with map above text to such kind of string array (eg :array[hrfeLink][value]). Hope some expert help me.
------------Updated---------------
According to the comment, I will try this way, and I can take the link location. But still couldn't take value.
let parser = new DOMParser();
let doc = parser.parseFromString(info, "text/html");
let x = doc.getElementsByTagName('a');
for (let i = 0; i < x.length ; i++) {
console.log(x[i].getAttribute('href'));
}
What is the value that you want? Is it the anchor text of the link?
We create an interface Link with the properties that we want from each link
interface Link {
location: string;
value: string;
}
Then we create a function that extracts all links from an html string and converts them to an array of Link objects.
function parseLinks( stringHTML: string ): Link[] {
// create a parser object
const parser = new DOMParser();
// turn the string into a Document
const doc = parser.parseFromString( stringHTML, "text/html" );
// get all links
const linkNodes = doc.getElementsByTagName('a');
// convert from HTMLCollection to array to use .map()
const linksArray = [...linkNodes];
// map from HTMLAnchorElement to Link object
return linksArray.map( element => ({
location: element.href,
value: element.innerText,
}))
}
Now you can do whatever with the links from your text
const text = `<html><body>A.txt
B.txt
D.txt
www.facebook.com
</body></html>`;
const links: Link[] = parseLinks( text );
// can use like this
links.map( ({location, value}) => {
// do something here
})
Typescript Playground Link

React + CSS Grid + MongoDB?

Im creating a webpage in which users can post stuff to a "bulletin board". These posts are gonna be styled as boxes, and I want to add them to a grid layout. This is my code:
import React from 'react';
//import Gallery from "./components/gallery.component"
function App() {
state = {
posts = [];
};
componentDidMount = () => {
this.getPosts();
};
getPosts = () => {
axios.get('(server)')
.then((response) => {
const data = response.data;
this.setState({ posts: data });
})
}
displayBlogPost = (posts) => {
if (!posts.length) return null;
return posts.map((post, index) => (
<div key={index} className="post__display">
<h3>"name " + this.state.name </h3>
</div>
));
};
render() {
return (
<div className="App">
<header className="container">
Logo
</header>
</div>
<div className="gallery">
{this.displayBlogPost(this.state.posts)} </div>
)
}
}
export default App;
Im a little unsure of how to work on the grid. Ive been looking into the CSS Grid documentation and I was wondering if it would be enough to keep my code as is and create a css file with an id #gallery that sets the attributes of the grid (display, grid-gap, repeat, etc). Would this be enough, or will I have to change my displayBlogPost function. I'm worried that the approach will consider gallery just containing one element and therefore there wont even be a grid.
Would appreciate some clarification and suggestions, I tried to find examples online, but none seemed to use react, mongodb, and css grid.
Its also hard because Im a newbie to React and MongoDB and JavaScript in general, but this project is for a hackathon and Im on a time crunch
Even though the post contains only one element the HTML DOM would show the grid in itself.
Yes, you can create a separate CSS file and include the req. CSS there.
Also, "name " + this.state.name you have not defined the state "name", how are you expecting for a display of value there?