I have an array with different values in state within my component.
I want to dynamically render different sections of an array to the same component but on different pages of my react app.
i.e Pass props down to Component that renders the first title of the array on one page but then render the second title on another page.
Can anyone help?
import React from 'react';
import ChartItem from './chart-item.component.js'
import Popup from './modal/index.js'
//styles
import './chart-slides.styles.css'
class Chart extends React.Component {
constructor() {
super();
this.state = {
sections: [
{
title: 'How do you compare to the competition?',
id: 'chart1',
iframeUrl: 'https://app.chattermill.io/c/f4a52535-b2b9-4d71-9ac7-e198c9452e3f?compact=true'
},
{
title: 'Main drivers of positive sentiment sentiment are brand, service, and app exeprience. While bugs and security features are big drivers of negative sentiment',
id: 'chart2',
iframeUrl: 'https://app.chattermill.io/c/f4a52535-b2b9-4d71-9ac7-e198c9452e3f?compact=true'
},
{
title: 'Scroll through the feedback to see the pain points for customers',
id: 'chart3',
iframeUrl: 'https://app.chattermill.io/c/f4a52535-b2b9-4d71-9ac7-e198c9452e3f?compact=true'
}
]
};
}
render() {
return (
<div>
{this.state.sections.map(({ id, title, iframeUrl }) => (
<ChartItem key={id} title={title} url={iframeUrl} />
))}
<Popup/>
</div>
);
}
}
export default Chart;
How can I only render the first section from my array in this component below? The component below will be showed in multiple pages within the app.
import React from 'react';
import Popup from '../modal/index.js'
import { Heading } from 'rebass'
import './chart-slides.styles.css'
import Iframe from 'react-iframe'
const ChartItem = ({ title, iframeUrl, id }) => (
<div>
<a className="demo-btn" id="demo-btn-chart1" href="https://app.hubspot.com/meetings/jack123/presentation" target="_blank" rel="noopener noreferrer"> Book Demo</a>
<Heading fontSize="2.8vh" textColor="secondary" className="mobile-chart-title" as='h1'>
{title}
</Heading>
<Iframe
url={iframeUrl}
className="iframe-container"
/>
</div>
);
export default ChartItem
Related
I am trying to return two things, a separate Mission component and a flat list. When I run my emulator, I can get the return on the Mission component but not the flat list. There are no errors, so I'm a bit lost with how to approach this issue. I even double-checked my imports. Here is the code:
import React, { Component } from "react";
import { ScrollView, Text, FlatList } from 'react-native';
import Mission from './Mission';
import PARTNERS from '../shared/partners';
import { ListItem } from 'react-native-elements';
class About extends Component {
constructor(props) {
super(props);
this.state = {
partners: PARTNERS,
}
};
static navigationOptions = {
title: 'About Us'
}
render() {
const { navigate } = this.props.navigation;
const renderPartner = ({ item }) => {
return (
<ListItem
title={item.name}
subtitle={item.description}
leftAvatar={{ source: require('./images/bootstrap-logo.png') }}
/>
);
};
return (
<ScrollView>
<Mission />
<FlatList
data={this.state.partners}
renderItem={renderPartner}
keyExtractor={item => item.id.toString()}
/>
</ScrollView >
);
}
}
export default About;
import React, { Component } from 'react';
import { FlatList, View, Text } from 'react-native';
import { ListItem, Card } from 'react-native-elements';
import { FILMS } from '../shared/films';
/*
When working correctly, when you hit "Tap to play" in the simulated mobile device to the right, you will see a list of films from shared/films.js.
Before updating this code:
- You must be logged into your Expo account (create an account if you do not have one already)
- Use the Save button on the upper right corner to fork this Snack to your account. Name it as you please, or accept the default random name.
Share the link to your version in the forum for this code challenge.
Your challenges: 1. Fix the component by adding a constructor and adding the data imported as FILMS to the component's state
2. In the FlatList, use that state data for films in the 'data' attribute.
3. In the ListItem, add the film title as the title, and the director as the subtitle.
4. Update films.js to add a third film of your choice.
Bonus Challenge: Write a custom view in the ListItem subtitle to show more details about each film, such as the release year, genre, language.
*/
class FilmCatalogue extends Component {
constructor(props) {
super(props);
this.state = {
films: FILMS
}
}
render() {
const renderFilm = ({item}) => {
return (
<ListItem
title={item.title}
titleStyle={{fontWeight: 700, color: 'dark-grey'}}
subtitle={
<View >
<Text style={{fontStyle: "italic", fontWeight: 500}}>{item.director}</Text>
<Text>{item.category}</Text>
<Text>{item.language}</Text>
</View>
}
rightSubtitle={item.year}
bottomDivider
/>
);
};
return (
<Card title="Film Catalogue">
<FlatList
data={this.state.films}
renderItem={renderFilm}
keyExtractor={item=>item.id.toString()}
/>
</Card>
);
}
}
export default FilmCatalogue;
i used this on an expo snack to display a list of the files i had in this file (the Film Catalogue Component.js)
hope this kind of helps!
I am trying to display images for an art gallery. I have one MainGallery component and within said Component is a Piece Component being rendered for each object in a helper file portfolio.js
The Piece Component is rendering for each object and I have access to the data from objects but the image path isn'y displaying images even though the file paths are correct.
MainGallery.js
import React, { useState } from 'react';
import portfolio from '../../portfolio';
import Piece from '../Piece/Piece';
export default function MainGallery() {
// const [pieces, setPieces] = useState(Object.keys(portfolio).map((x) => x));
return (
<div>
{Object.keys(portfolio).map((key) => (
<Piece
key={key}
index={key} // if we need access to key we need to pass it down as prop as something other than 'key'
details={portfolio[key]}
/>
))}
</div>
);
}
Piece.js
import React from 'react';
export default class Piece extends React.Component {
render() {
// deconstruct properties for Piece
const { title, imgPath, description } = this.props.details;
return (
<div className="single-piece">
{console.log(imgPath)}
<h1>{title}</h1>
<img src={imgPath} alt={title} />
<p>{description}</p>
</div>
);
}
}
portfolio.js
const portfolio = [
{
title: 'Storm',
imgPath: '../../images/storm.jpg',
description: 'An owl done with ',
type: 'misc',
style: 'acrylic',
},
{
title: 'eagle',
imgPath: '../../images/eagle.jpg',
description: 'A bald eagle in the wild',
type: 'pet',
style: 'paint',
},
{
title: 'family',
imgPath: '../../images/family.jpg',
description: 'A portrait of my son and nieces.',
type: 'people',
style: 'pastel',
},
];
export default portfolio;
Try using require in the src path.
<img src={require(imgPath)} alt={title} />
If that doesn't work, create a js file in the images folder and export the images like this:
export const poster1 = require('./storm.jpg');
The third option would be to try to import all the images in your component, but that would require a lot more changes to your code.
import storm from '../../images/storm.jpg'
and the final thing to try would be to make sure you keep all your images in the public folder instead of src. Then access them like so:
<img src='/images/storm.jpg' />
Hope that helps.
I have a React component that maps data from a .js file, containing objects in array. How can I link my title and images from within this function to access respective pages.
The title of an array of objects is 'Practices' which should open a new practices page when clicked. Within this object, there are a number of items, each of which contain an image of a practice, which when clicked must go to that specific practice page.
Here is sample code from my Practice_Data File..
const PRACTICES_DATA = [
{
id: 1,
title: 'Practices',
routeName: 'practices',
items: [
{
id: 1,
name: 'Defending Centrally | Opposed Skill (12-P5)',
imageUrl: 'https://image.mux.com/D8PU0036BeX3veIIzAKJlqiECDBoEIJak/animated.gif?width=490&height=278&fps=15',
Theme: 12,
},
]
},
export default PRACTICES_DATA;
Here is the code for my practice component:
import React from 'react';
import PRACTICES_DATA from './practices.data';
import CollectionPreview from '../../components/collection-preview/collection-preview';
class PracticesPage extends React.Component {
constructor(props) {
super(props);
this.state = {
collections: PRACTICES_DATA
};
}
render() {
const {collections} = this.state;
return (
<div className='practices-page'>
{collections.map(({ id, ...otherCollectionProps }) => (
<CollectionPreview key={id} {...otherCollectionProps} />
))}
</div>
);
}
}
export default PracticesPage;
There might well be an obvious answer to this, but I have been stuck on this for a while. Any help would be greatly appreciated.
EDIT:
Yes using react router here. The Collection Preview Code is shown below:
import React from 'react';
import CollectionItem from '../collection-item/collection-item.component';
import './collection-preview.styles.scss';
const CollectionPreview =({ title, items }) => (
<div className='collection-preview'>
<h1 className='title'>{title.toUpperCase()}</h1>
<div className='preview'>
{items.filter((item, idx) => idx < 4)
.map(({ id, ...otherItemProps }) => (
<CollectionItem key={id} {...otherItemProps} />
))}
</div>
</div>
);
export default CollectionPreview;
I'm building a KanBan app with ReactJS, and I'm trying to pass state from a parent component to the furthest component in the parent-child tree. I have a Column component within my main App component, and within this Column component there is another component called 'Card'. I want to pass the data the gets added/updated in the state of the App component & successfully display it in the Card component. As its obvious by now, the Card component is the child of the Column component.
I tried doing so with this.props but this only works one level down - with the column component. I thought about declaring a variable and equating to this.props.details.cards, and then setting it as the new state of the column component so that I could pass it again as props to the card component, but I assume this is not best practice.
This is my App Component:
class App extends Component {
constructor(props) {
super(props)
this.state = {
columns: [
{
name: 'Todos',
cards: []
},
{
name: 'Onprogress',
cards: []
},
{
name: 'Done',
cards: []
},
]
};
};
addCard = card => {
console.log("Adding a Card");
const cards = { ...this.state.columns.cards };
const keyDate = `card${Date.now()}`
cards[keyDate] = card;
this.setState({
columns: [
{
name: 'Todos',
cards: cards
}
]
});
};
render() {
return (
<div className="App">
{Object.keys(this.state.columns).map(key => (
<Column key={key} details={this.state.columns[key]} />
))}
<AddCardForm addCard={this.addCard} />
</div>
);
}
}
export default App;
This is my Column Component:
import React, {Component} from "react";
import Card from "./Card"
class Column extends Component {
render() {
return (
<div className="column">
<h1 className="Title">{this.props.details.name}</h1>
<Card />
</div>
);
}
}
export default Column;
And this is my Card Component:
import React, {Component} from "react";
class Card extends Component {
render() {
return (
<div className="card">
<span className="title">I'm a Card!</span>
</div>
);
}
}
export default Card;
React will only get the properties that are injected into the child component.
Considering we have three component A , B and C.
If we want to pass a prop from A to C while B is in the middle, we do this:
The A component returns the B component and passes someProperty as follows:
return <B someProperty={someValue} />
Now, in the B component we can access the property by calling it this.props.someProperty however, it won't be available at the C component, if we want to do so, we do the following.
return <C someProperty={this.props.someProperty} />
What we did in component B is pass the someProperty that came from component A which we can access in B as this.props.someProperty, we pass it again the same way to the component C..
Read more about this: Passing props between react component
Full example as follows:
Component A:
render() {
return (
<B someProperty={'someString'} />
);
}
Component B:
render() {
return (
<C someProperty={this.props.someProperty} />
);
}
Compoent C: to access the property someProperty for example in the render method
render() {
return (
<p>{this.props.someProperty}</p>
);
}
I am trying to output some svgs and output them from a list, here is my render method:
render() {
const renderTag = () => {
const Tag = this.props.id
return(<Tag />)
}
return (
<div key={this.props.name} className="social-box">
<a className={this.props.id + "-link"}>
{renderTag()}
</a>
</div>
)
}
However, the DOM node is always lowercase i.e. <facebook> rather than <Facebook> this.props.id is correctly rendered to the console as Facebook. Can anyone tell me why react or the browser incorrectly renders as lowercase, and therefore not the component, and how to fix?
It's a technical implementation of React, all tags get lowercased on this line here, AFAIK it's not possible to render non-lowercased tags and that is by design.
Read more here.
i suggest that you would take a look at this article about dynamic components.
The most relevant example from the article:
import React, { Component } from 'react';
import FooComponent from './foo-component';
import BarComponent from './bar-component';
class MyComponent extends Component {
components = {
foo: FooComponent,
bar: BarComponent
};
render() {
const TagName = this.components[this.props.tag || 'foo'];
return <TagName />
}
}
export default MyComponent;
you most likely have a limited amount of components that could be rendered, so you might create a dictionary that contain a key (name of the component) to the component itself (as shown in the example) and just use it that way:
import Facebook from './FaceBook';
import Twitter from './Twitter';
const components = {
facebook: Facebook,
twitter: Twitter
};
render() {
return <div key={this.props.name} className="social-box">
<a className={this.props.id + "-link"}>
<components[this.props.id] />
</a>
</div>;
}
I find the answer eventually. #TomMendelson almost had the answer, but it needed fleshing out a bit more.
A function to create the component outside of the render method, suggested by #ShubhamKhatri actually did the job. Here's the final code:
import React from 'react';
import Facebook from './svg/Facebook';
import LinkedIn from './svg/LinkedIn';
import Twitter from './svg/Twitter';
import Pinterest from './svg/Pinterest';
class SocialMediaBox extends React.Component {
renderElement(item) {
const Components = {
'Facebook': Facebook,
'Twitter': Twitter,
'Pinterest': Pinterest,
'LinkedIn': LinkedIn
}
return React.createElement(Components[item], item);
}
render() {
const Element = this.renderElement(this.props.id)
return
(
<div>
{Element}
</div>
)
}
}
export default SocialMediaBox;
Thanks for the question and answers; alongside the answers given in Dynamic tag name in jsx and React they helped me to find a solution in my context (making a functional component in Gatsby with gatsby-plugin-react-svg installed):
import React from "react"
import FirstIcon from "../svgs/first-icon.inline.svg"
import SecondIcon from "../svgs/second-icon.inline.svg"
import ThirdIcon from "../svgs/third-icon.inline.svg"
const MyComponent = () => {
const sections = [
{ heading: "First Section", icon: () => <FirstIcon /> },
{ heading: "Second Section", icon: () => <SecondIcon /> },
{ heading: "Third Section", icon: () => <ThirdIcon /> },
]
return (
<>
{sections.map((item, index) => {
const Icon = item.icon
return (
<section key={index}>
<Icon />
<h2>{item.heading}</h2>
</section>
)
})}
</>
)
}
export default MyComponent
As mine is a Gatsby project I used the above mentioned plugin, but it itself process svgs with svg-react-loader so the basic principle should work in any React project using this package.