React - how to create a dynamic (using router) details pages - javascript

This is my data (in a seperate JS file):
const someData= [
{
id: 1,
title: "Article 1",
desc: "Some description lorem ipsum",
},
{
id: 2,
title: "Article 2",
desc: "Some description lorem ipsum",
},
{
id: 3,
title: "Article 3",
desc: "Some description lorem ipsum",
}
]
export default someData;
Now I'm mapping the data like this:
- Articles.js file
const articleItems = this.state.someData.map(item =>
<ArticleItem key={item.id} item={item}
/>)
return(
<div>{articleItems}</div>
)
And listing all articles with only the article title displayed in ArticleItem component.
- articleItem.js file
return(
<h1>{props.item.title}</h1>
)
How can I create so you can click on an article title in the list, which would then go to that specific article (url should be /article/id) and display all data for that specific article?

Use React Routers Version 4 to achiever this.
Article.js file-
const articleItems = this.state.someData.map(item =>
<Route key={item.id} path=`/${item.title}/${item.id}` render={
<ArticleItem
{...props}
item={item}
/>
} />
/>)
return(
<div>{articleItems}</div>
)
In the file where you are rendering the Links render like this.
render() {
return(
<Link to=`/${item.title}/${item.id}`>{item.title}</Link>
);
}
Don't forget to import Route and Link.
Hope this helps.

Related

Mapping over an array to render images

I am trying to create cards that display an image with a description. I have an array with the data for each card. The cards are appearing with the description, but the images aren't rendering.
The Card Component:
export const Card = (props) => (
<div className="card">
<a href={props.href} target="_blank">
<img className="card-image" src={props.src} alt={props.alt} />
<h3 className="card-title">{props.title}</h3>
<p className="card-description">{props.description}</p>
</a>
</div>
);
A Callback Function and the Projects component that maps through the array:
const renderCard = (project) => (
<Card
href={project.href}
src={project.src}
alt={project.alt}
title={project.title}
description={project.description}
key={project.id}
/>
);
const Projects = () => {
const cardElements = projects.map(renderCard);
return (
<div id="projects-section">
<h1 className="title">Projects</h1>
{cardElements}
</div>
);
};
And the data is coming from this projects array:
import retreat from "../images/retreat.jpg";
import guess from "../images/guessTheWord.jpg";
import jsKeyboard from "../images/drum-kit.jpg";
import ptWebsite from "../images/ptWebsite.jpg";
import stickyNotes from "../images/sticky-notes-app.jpg";
import firstWebsite from "../images/my-first-website.jpg";
export const projects = [
{
href: "https://patgramo.github.io/unplugged-retreat/",
src: { retreat },
alt: "Card image",
title: "Company Retreat Website",
description:
"I created a website for a company retreat to practice using media queries with CSS. This was a project through Skillcrush.",
id: "01"
},
{
href: "https://patgramo.github.io/guess-the-word/",
src: { guess },
alt: "Card image",
title: "Guess The Word Game",
description:
"Here I created a guess-the-word game using my JavaScript and CSS knowledge. This was the final project in Skillcrush's JavaScript course.",
id: "02"
}
];
The values you're setting for src are objects, not strings. On your first entry src is an object with a retreat property. Remove the curlies.
{
href: "https://patgramo.github.io/unplugged-retreat/",
src: retreat,
alt: "Card image",
title: "Company Retreat Website",
description:
"I created a website for a company retreat to practice using media queries with CSS. This was a project through Skillcrush.",
id: "01"
},

Is it nessesary to use getStaticProps with json import in Next.js?

I want to render static data that is coming from a JSON or typescript file and display it to the user. Do I have to use getStaticProps or can I simply import the data without getStaticProps? It's not clear to me after reading the next documentation.
projects.tsx
const projects: [
{
id: "6853939";
name: "Project 01";
title: "Title 01 ";
previewImg: "/images/projectThumbnails/image01.jpg";
},
{
id: "6853939";
name: "Project 02";
title: "Title 02 ";
previewImg: "/images/projectThumbnails/image02.jpg";
}
];
export default projects;
names.json
{
"names": [
{ "name": "Full Name 01", "age": 34 },
{ "name": "Full Name 02", "age": 22 },
],
}
index.tsx
import projects from "../data/projects.tsx";
import names from "../data/names.json";
const IndexPage = () => {
return (
<>
<div>
{projects.map((i) => (
<div key={i.id}>{i.title}</div>
))}
</div>
<div>
{names.names.map((i) => (
<div key={i.name}>{i.name}</div>
))}
</div>
</>
);
};
It's totally up to you which approach you are going to use .
With getStaticProps:
server uses JSON data to inject data and create cache
Without getStaticProps:
JSON file would be injected in client side , without being cached
I prsonally recommend using getStaticProps
Importing JSON in getStaticProps:
import yourJson from ('./somefile.json')
export async function getStaticProps(context) {
//use your json here
return {
props: {}, // will be passed to the page component as props
}
}

How to access the value inside array of object within that array

Update:
Basically i want the same output but i restructured the content. I'm not sure if your answers are still up for that.
Please check my sandbox feel free to fork it here:
https://codesandbox.io/s/get-the-property-value-forked-hutww
So on ContentData.js i want my image alt tag to be dynamic and pull the content of it from key name it something like this alt={this.name} and it will generate to alt="My alt tags"
See the codes below:
Content.js
import React, { Component } from "react";
import mainListsItems from "./ContentData";
class Content extends Component {
render() {
const myContent = mainListsItems.map((lists, k) => (
<>
<div key={k}>{lists.text}</div>
{lists.mainContent.map((subcontent, j) => {
return <div key={j}>{subcontent.contentAll}</div>;
})}
</>
));
return <>{myContent}</>;
}
}
export default Content;
ContentData.js
import React from "react";
const listsData = [
{
id: 1,
name: "My alt tags",
text: (
<>
<p>Lorem Imsum</p>
</>
),
mainContent: [
{
contentAll: (
<>
<p>
Lorem Ipsum is simply dummy text of the printing and typesetting
industry.
</p>
<img
alt=""
src="https://images.unsplash.com/photo-1637704758245-ed126909d374?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxNHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60"
/>
</>
)
}
]
}
];
export default listsData;
content is defined inside the object while the object is being defined. So there is no name yet when content is being defined. Only after the assignment does name exist. You're referencing something that doesn't exist yet. So instead you can create a function that will be called at a later point after the object is defined and then the name can be referenced as shown below.
export default function App() {
const myData = [
{
id: 1,
name: "Lorem Ipsum",
content: function(){
return (
<>
<img
src="https://images.unsplash.com/photo-1637704758245-ed126909d374?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxNHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60"
alt={this.name}
/>
</>
)
}
}
];
const output = myData.map((x) => (
<>
<div key={x.id}>
<p>{x.name} sa</p>
<p>{x.content()}</p>
</div>
</>
));
return <div className="App">{output}</div>;
}
The this, in your case is referring the window object.
You can try to pass the name as a function value.
Something like this :
const myData = [
{
id: 1,
name: "Lorem Ipsum",
content: (alt) => (
<>
<img
src="https://images.unsplash.com/photo-1637704758245-ed126909d374?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwxNHx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60"
alt={alt}
/>
</>
)
}
];
const output = myData.map((x) => (
<div key={x.id}>
<p>{x.name} sa</p>
<p>{x.content(x.name)}</p>
</div>
));
You can replace the object in your myData array with a self executing function like this:
const myData = [
function(){
const entry = {
id: 1,
name: "Lorem Ipsum",
}
return {
...entry,
content: (
<>
<img
src="your image source"
alt={entry.name}
/>
</>
)
}
}()
];

Antd how to use a kind of onLoad or componentDidMount function?

I am working with AntDesign and want to use a onLoad or a componentDidMount function. Both don't work.
How can I make a function with the same purpose?
//Things I have tried and didn't work for me. (I might be doing things wrong.)
return (
<div onLoad={() => {console.log('Toeter!')}}>
//Blah blah
</div>
)
window.onload = () => {
//Blah blah
}
componentDidMount = () => {
//Blah blah
}
What I want to do is trigger a function when the components comes on screen. The funtion is supposed to find a product in an array of objects.
EDIT:
A complete component as asked in the comments
import * as React from "react";
import {Row, Col, Image, Card, Space, Breadcrumb, Descriptions, InputNumber, Button} from 'antd';
import * as FreddieGras from "../images/freddieGras.jpg";
import "react-multi-carousel/lib/styles.css";
import {RouterProps} from "./router.props";
import {Link} from "#reach/router"
interface ProductDetailProps extends RouterProps {
id?: string;
}
export default function ProductDetail(props: ProductDetailProps) {
// Different kinds of grass
let grassKinds = [
{
name: 'Kate',
id: 1,
imageName: FreddieGras,
desc: "Lorem Ipsum dolor sit amet.",
available: true,
softness: 7,
realness: 6,
price: 17.95
},
{
name: 'Fred',
id: 2,
imageName: FreddieGras,
desc: "Lorem Ipsum dolor sit amet.",
available: false,
softness: 7,
realness: 6,
price: 17.95
},
{
name: 'Gideon',
id: 3,
imageName: FreddieGras,
desc: "Lorem Ipsum dolor sit amet.",
available: true,
softness: 7,
realness: 6,
price: 17.95
},
{
name: 'Isa',
id: 4,
imageName: FreddieGras,
desc: "Lorem Ipsum dolor sit amet.",
available: true,
softness: 7,
realness: 6,
price: 17.95
},
];
let product = {};
window.onload = () => {
product = grassKinds.find(x => x.id);
console.log('Toeter!');
}
return (
<div onLoad={() => {
console.log('Toeter!')
}}>
<Breadcrumb>
<Breadcrumb.Item>
<Link to="/">Home</Link>
</Breadcrumb.Item>
<Breadcrumb.Item>
</Breadcrumb.Item>
</Breadcrumb>
<Row>
<Col span={10} justify={'space-around'} align={'center'}>
<Image
src={FreddieGras}
/>
</Col>
<Col span={14}>
<Descriptions title="User Info" style={{width: '50%'}}>
<Descriptions.Item label="Naam">Kate</Descriptions.Item>
<Descriptions.Item label="Zachtheid">7/10</Descriptions.Item>
<Descriptions.Item label="Echtheid">6/10</Descriptions.Item>
<Descriptions.Item label="Prijs /m2">€17,95</Descriptions.Item>
</Descriptions>
<Card title="Bereken oppervlakte" style={{margin: '5px'}}>
<label>Lengte (m)</label>
<InputNumber
defaultValue={1000}
formatter={value => `€ ${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}
onChange={() => {
console.log('Number')
}}
/>
<div>
<p><b>Omtrek </b> 10 M</p>
<p><b>Oppervlakte </b> 2,5 M2</p>
</div>
</Card>
<Card title="Totaalprijs" style={{margin: '5px'}}>
<b>€ 17,95</b>
<Button onClick={() => {
console.log('In winkelwagen')
}}>In winkelwagen</Button>
</Card>
</Col>
</Row>
</div>
)
}
React components don't use window.onload and componentDidMount is reserved for and valid only in class-based components. Functional components can use an useEffect React hook with empty dependency array to have the equivalent to componentDidMount lifecycle method.
let product = {};
useEffect(() => {
product = grassKinds.find(x => x.id);
console.log('Toeter!');
}, []);

Pass Component from JS Object as props in React

I'm reading from a JS object (from JSX) and trying to pass value of a component but it's rendered as string.
I tried placing components (in icon key of data see below) in {} but that doesn't help as data gives an error.
Here's the simplified version of the files.
data.js as below:
const data = [
{
title: "some title",
desc: "some desc",
},
[
{
icon: "<TwitterIcon />",
title: "title 1",
desc: "desc 1",
},
{
icon: "<FacebookIcon />",
title: "title 2",
desc: "desc 2",
},
],
]
export { data }
index.js that reads data object and passes as props to AnotherComponent:
import { data } from "../path/to/data"
import AnotherComponent from "../path/to/AnotherComponent"
const Homepage = () => {
return (
<AnotherComponent {...data} />
)
}
AnotherComponent.jsx as below:
import {TwitterIcon, FacebookIcon} from "../path/to/CustomIcons"
const AnotherComponent = ({ ...data}) => {
return (
{data[1].map(item => (
<div>{item.icon}</div> // this prints string as opposed to rendering the component
<div>{item.title}</div>
<div>{item.desc}</div>
))}
)
}
index.js returns:
<div><TwitterIcon /></div>
<div>title 1</div>
<div>desc 1</div>
<div><FacebookIcon /></div>
<div>title 2</div>
<div>desc 2</div>
In the object you are defining as:
{
icon: "<TwitterIcon />",
title: "title 1",
desc: "desc 1",
}
Don't use "<TwitterIcon />" It will always return a string, instead use TwitterIcon:
{
icon: TwitterIcon,
title: "title 1",
desc: "desc 1",
}
And finally, call it where you need it, in this way:
const AnotherComponent = ({ ...data}) => {
return (
{data[1].map(item => (
<div><item.icon /></div> // HERE: check I'm calling item.icon as React Component
<div>{item.title}</div>
<div>{item.desc}</div>
))}
)
}
In this way you are passing the icon to anywhere you want and not just passing a string. So, you can call it as a Component when you need it to render. I do it a lot in my work.
I think you should pass directly the icon component in the object, like this:
const data = [
{
title: "some title",
desc: "some desc",
},
[
{
icon: <TwitterIcon />,
title: "title 1",
desc: "desc 1",
} ...
Then in index.js you can do (it is more clear to pass down props like this):
const Homepage = () => {
return (
<AnotherComponent data={data} />
)
}
In AnotherComponent.jsx now you can do:
const AnotherComponent = ({data}) => {
return (
{data[1].map(item => (
<div>{item.icon}</div>
<div>{item.title}</div>
<div>{item.desc}</div>
))}
)
}

Categories

Resources