React render gif files from JSON - javascript

I have data from a local JSON file. Each record has some text (string) and a map saved as .gif. The gif files I put in a folder inside ./src.
I need to reference the right map (gif file) to the right record.
Structure of JSON data file:
[
{
"id": "someid",
"text": "some text",
"map": "map name"
},
...
]
I have a component like this:
const Story = ({obj}) => (
<Card className="item" id={obj.id}>
{
obj.map
? (<div className="card-img-none"></div>)
: (<div className="card-img"></div>)
}
<CardBody>
<CardTitle>{obj.text}</CardTitle>
{
obj.map
? (<div className={obj.map}></div>)
: null
}
</CardBody>
</Card>
)
And render the Story component:
import data from './data.json';
...
<div>
{
this.state.data
? (
this.state.data.map((i) => (
<Story obj={i} key={i.id}/>
))
)
: ('Data not found')
}
</div>
Since the maps are gif, I've tried these:
import each gif and set if then statement to check if object.map == gif file name and render the gif file as <img src={mapName}/>, set css img {width: 100%}. This works only for one record since others have map key-value pair.
create a class in index.css for each map (e.g .mapName {background: url('./gif-file.gif') center no-repeat; background-size: cover; Then render the map like the code above. It works for all of them.
However, I run into the issue that I have to set the width and height of the map div to fixed value, setting width: 100% or height: 100% doesn't work. The values turn 0.
It seems like there must be a better solution for this. Any idea?

In case you have the same issue, I've figured out a workaround (it works but I'm not sure it's the best practice):
import data from './data.json'; // Import data from json file
import map from '<relative path>/map.gif'; // Import gif file with relative path
// Inside the class
constructor(props) {
super(props);
this.state = {
data: []
};
}
componentDidMount = () => {
data[3].map = map; // Add value to key 'map' of the target element in data array
this.setState({data});
}
Hope this helps.

Related

How can I put a JSON object into JSX?

I have a json array that contains some information :
[
{
"id": 1,
"imageUrl": "./img1.png",
},
{
"id": 2,
"imageUrl": "./img2.png",
}
]
I tried to make a class in which the elements were sorted and added the necessary link to the src, but the information from JSON is not put into JSX.
class Paintings extends Component {
render(){
return(
<ul>
{
paintings.map((s) => {
return (
<div>
<img src={s.imageUrl} alt={s.id} />
</div>
)
})
}
</ul>
)
The question is more general then just about images here. It is to import and loop a JSON object in JSX.
You have some syntax error in your code, I fixed them and shared an online editor implementation for you to have a look as well.
Save your json in a file and import that file in your react code then map the json object.
For the images location, although this is not the recommended method, I think you should put your images under public folder and make sure you have your json file with the correct path.
Sample JSON file I have structured, for your reference:
[
{
"id": 1,
"imageUrl": "image1.png"
},
{
"id": 2,
"imageUrl": "image2.png"
}
]
Then you should be able to use below code to be able to generate it.
import React, { Component } from "react";
import Painting from "./Painting";
class Paintings extends Component {
render() {
return (
<ul>
{Painting.map(({ id, imageUrl }) => (
<div key={id}>
<img src={imageUrl} alt={id} />
</div>
))}
</ul>
);
}
}
export default Paintings;
Here is a basic implementation for you to check out, we are able to map and see the items. I have added some sample images and please pay attention to json file and how its ready to map the JSX image objects based on the file paths.
https://codesandbox.io/s/react-json-into-jsx-19gj1w

How to return a component/component-tag dynamically in vue/nuxt?

I am trying to convert a next.js app(https://medium.com/strapi/how-to-create-pages-on-the-fly-with-dynamic-zone-8eebe64a2e1) to a nuxt.js app. In this app I can fetch data from an API and the next.js app uses the APIs data to generate new pages with its corresponding content. Works well in Next.js.
The data/content from the API consists of Seo data for the page, some static values and very important of blocks. These blocks have an attribute called __component where the components name is saved and also have the components data like images, text, etc. So I only have to deal with next.js when adding new components.
In next.js I used the catch-all-route ./pages/[[...slug]].js to catch any slug an user may enter. Then the API is fired with the slug from the context.query and I get back the pages data if it exists. Now the APIs json data only needs to be passed to the blockmanager component.
const Universals = ({blocks}) => {
return <div><BlockManager blocks={blocks}></BlockManager></div>;
};
Here the blockmanager gets the json list of blocks, from which to parse the components.
import Hero from '../../blocks/Hero';
import Pricing from '../../blocks/Pricing';
const getBlockComponent = ({__component, ...rest}, index) => {
let Block;
switch (__component) {
case 'blocks.hero':
Block = Hero;
break;
case "blocks.prices":
Block = Pricing;
break;
}
return Block ? <Block key={`index-${index}`} {...rest}/> : null;
};
const BlockManager = ({ blocks }) => {
return <div> {blocks.map(getBlockComponent)} </div>;
};
BlockManager.defaultProps = {
blocks: [],
};
export default BlockManager;
How can I replicate this line now in nuxt js?
return Block ? <Block key={`index-${index}`} {...rest}/> : null;
How to return a component/component-tag dynamically in vue/nuxt ?
Is there maybe another solution to automatically insert the wanted component?
Maybe someones knows ho to convert the blockmanagers logic to vue/nuxt logic entirely.
I think you're looking for the is attribute. You can read about it here.
Your template would look like:
<component
:is="__component"
key={`index-${index}`}
/>
Ok I think I got it. No strange stuff actually. I thought about it too complicated. Wanted all dynamically created but no need as I saw later ...
<template v-if="blocks">
<div id="example-1">
<div v-for="({__component, ...rest}=block, i) in blocks" :key="i">
<Hero :data="rest" v-if="__component === 'blocks.hero'"/>
<Pricing :data="rest" v-if="__component === 'blocks.pricing'"/>
</div>
</div>
</template>
<script>
import Hero from '../../blocks/Hero/Hero.vue';
import Pricing from '../../blocks/Pricing/Pricing.vue';
export default {
components: {
Hero, Pricing
},
props: {
blocks: Array
}
}
</script>

Dynamically rendered images in Gatsby

I'm working on the blog based on React, TS and Gatsby.
Blog posts are based on markdown. Each blog post will have a similar header with title, time necessary to read the article and the logos of the technologies that the particular blog post will be about.
I have a problem with rendering those images dynamically. My idea was to create something like this in markdown
---
path: "/fourth"
date: "2021-06-02"
title: "TypeScript - intro"
readTime: "140"
author: "Adam Kniec"
imgs: [typescript, react]
---
That's the fourth blog post
after that I wanted to create a graphql query and get the imgs names like so:
export const postQuery = graphql`
query BlogPostByPath($path: String!) {
markdownRemark(frontmatter: { path: { eq: $path } }) {
html
frontmatter {
path
readTime
title
author
imgs
date
}
}
}
`;
I have the array of images in the props now and I wanted to render those images like this
{data.markdownRemark.frontmatter.imgs.map((imgPath) => {
const imgPatha = `../images/${imgPath}`;
return <StaticImage src={imgPatha} alt="asdasd" />;
})}
Unfortunately, gatsby gives me the warning
react_devtools_backend.js:2560 Image not loaded ../images/typescript
Is this the correct approach ? Please let me know what I'm doing wrong or how to render those images dynamically.
As it has been said by #coreyward you can't use dynamic props in the StaticImage component, it's a known restriction.
That said, you have two choices:
Using the standard img HTML tag.
Using the GatsbyImage component. To do it, you'll need to add the images in your filesystem to allow Gatsby to create the proper nodes and then, you will need to query them in your pages/templates. Without further details on the implementation, it's impossible to guess how your code should look like but the idea relies on something like:
import { graphql } from "gatsby"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
function BlogPost({ data }) {
const image = getImage(data.blogPost.avatar)
return (
<section>
<h2>{data.blogPost.title}</h2>
<GatsbyImage image={image} alt={data.blogPost.author} />
<p>{data.blogPost.body}</p>
</section>
)
}
export const pageQuery = graphql`
query {
blogPost(id: { eq: $Id }) {
title
body
author
avatar {
childImageSharp {
gatsbyImageData(
width: 200
placeholder: BLURRED
formats: [AUTO, WEBP, AVIF]
)
}
}
}
}
`

GatsbyJS - TypeError: Cannot read property 'childImageFluid' of undefined

I am working on a Gatsby website, and I keep getting "TypeError: Cannot read property 'childImageFluid' of undefined"
The code I have is this in my Project.js file
import React from "react"
import PropTypes from "prop-types"
import Image from "gatsby-image"
import { FaGithubSquare, FaShareSquare } from "react-icons/fa"
const Project = ({description, title, github, stack, url, image, index}) => {
return (
<article className="project">
<Image fluid={image.childImageFluid.fluid} className="project-img" />
</article>
)
}
Project.propTypes = {}
export default Project
and I have the graphql set up in the index.js file where it will be displayed, and everything is working as it should in graphql...
export const query = graphql`
{
allStrapiProjects(filter: { featured: { eq: true } }) {
nodes {
github
id
description
title
url
image {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
stack {
id
title
}
}
}
}
`
everything up to the what I am working on in the Project.js file is in my github - https://github.com/matthewbert86/gatsby-site but all of that code is in the first code section above.
When you use a page query in GraphQL, your gathered data is stored inside a data object (as a props). You need to iterate through it until you get your fluid image. It should be in: props.data.allStrapiProjects.nodes.image.childImageFluid.fluid. Since you are destructuring everything in your <Project> component:
const Project = ({ data }) => {
let { description, title, github, stack, url, image } = data.allStrapiProjects.nodes; // your data is here
return (
<article className="project">
<Img fluid={data.allStrapiProjects.nodes.image.childImageFluid.fluid} className="project-img" />
</article>
)
}
After destructuring, you can refactor it to:
<Img fluid={image.childImageFluid.fluid} className="project-img" />
Another point, I guess that the gatsby-image import should be Img, not Image.

Changing background image in ReactJS

I am currently working on a weather app that changes background based on time of the day and the weather description. I created a state that handles the background style of the page.
class App extends React.Component {
constructor() {
super();
this.state = {
city: undefined,
country: undefined,
localtime: undefined,
timezone: undefined,
temperature: undefined,
precip: undefined,
humidity: undefined,
weather_icon: undefined,
weather_description: "",
error: false,
backgroundStyle: {
backgroundImage: undefined,
backgroundColor: 'black',
backgroundPosition: 'center',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat'
}
};
}
I also created a function that handles the logic of the background change. In it also is an array holding the images for the background. For example,
const bgImage = [
"",
"'url(img/snowy.jpg)'",
"'url(img/night.jpg)'",
"'url(img/sunny.jpg)'",
"'url(img/stormy.jpg)'",
"'url(img/sunset.jpg)'",
"'url(img/night-rain.jpg)'",
"'url(img/snow-night.jpg)'"
]
// Check for rain
if (description === 'showers' || description.includes('rain')) {
if (time >= 20 || (time >= 0 && time < 7)) {
this.setState({
backgroundStyle: {
backgroundImage: bgImage[6]
}
});
} else if (time > 7 && time < 20) {
this.setState({
backgroundStyle: {
backgroundImage: bgImage[0]
}
});
} else {
this.setState({
backgroundStyle: {
backgroundImage: bgImage[0]
}
});
}
}
In the render function, I return a div and with the style
<div className="App" style={this.state.backgroundStyle}>
The images do not load and I am not exactly sure what I'm doing wrong. Any help please. Thanks.
First of all, I'd highly recommend you to store this kind of static files on a CDN, it will make your client lighter!
But, if you want to use a local image you have two choices.
You can import the image file and use it like any other imported object.
import snowy from '../../snowy.jpg';
import night from '../../night.jpg';
import sunny from '../../sunny.jpg';
import stormy from '../../stormy.jpg';
import sunset from '../../sunset.jpg';
import nightRain from '../../night-rain.jpg';
import snowNight from '../../snow-night.jpg';
const bgImage = [
"",
snowy,
night,
sunny,
stormy,
sunset,
nightRain,
snowNight,
]
or
You need to provide the relative path to the folder, for example: ../../img/snowy.jpg, remember that the relative path refers to the current file in which the path is written.
edit:
You can also use something like:
const bgImg = `url(${this.state.backgroundStyle.backgroundImage})`
Once your url() is under "" Webpack won't be able to find the images later at runtime.
try using:
import logo from './logo.png'; // this will tell webpack that you are using this file, therefore it will be included like logo.<chunk>.png
it would be because you are wrapping the strings in the bgImage array in single and double quotes at the same time

Categories