Styling some parts of my React JSX rendered elements with CSS - javascript

I have an array of data that I'm mapping through in my small react project to render the contents of the data into the browser. But my problem is that I need to style some parts of these rendered contents and not all. Each of the CSS properties I'm applying is applicable to all the P tags. For Example, in the code below, The style will be applicable to Was, to Birthday in the second item, and so on...
Below is my CSS code.
import React from "react";
import "./styles.css";
export default function App() {
const data = [
{
details: 'Yesterday was his birthday'
},
{
details: 'Today is my birthday'
},
{
details: 'I cant\'t remember my birthday date'
}
]
return (
<div className="App">
<h1>I need Help</h1>
<h2>Please How do i style some parts of my rendered details</h2>
{
data.map((detail)=>(
<p>{detail.details}</p>
))
}
</div>
);
}

You can add a highlight prop to your array elements and split the sentence by that prop. Then, put the split word in its own span between the pieces.
export default function App() {
const data = [
{
details: 'Yesterday was his birthday',
highlight: 'was'
},
{
details: 'Today is my birthday',
highlight: 'birthday'
},
{
details: 'I cant\'t remember my birthday date',
highlight: 'date'
}
]
return (
<div className="App">
<h1>I need Help</h1>
<h2>Please How do i style some parts of my rendered details</h2>
{data.map((datum) => {
const pieces = datum.details.split(datum.highlight);
return (
<p key={datum.details}>
{pieces[0]}
<span style={{ backgroundColor: "#FF0" }}>{datum.highlight}</span>
{pieces[1]}
</p>
);
})}
</div>
);
}

There are many ways to solve this problem. Then one suggested by #Nick is decent. You can also check my suggestion.
export default function App() {
const data = [
{
details: 'Yesterday was his birthday',
css: true
},
{
details: 'Today is my birthday',
css: false
},
{
details: 'I cant\'t remember my birthday date',
css: false
}
]
return (
<div className="App">
<h1>I need Help</h1>
<h2>Please How do i style some parts of my rendered details</h2>
{
data.map((detail)=>(
<p className={detail.css ? 'my-custom-class' : ''}>{detail.details}</p>
))
}
</div>
);
}
With this approach you will not have <p class="undefined">...</p>

Related

How to use images in the array in the react?

I am creating a website. I am a beginner. I have an issue. I have an array of react components. I don’t know can I use React components as the array elements. They are images, imported from the folder of my project. Also, I have an array of names of news companies. The idea is to create blocks with the name and image above. I want to create blocks according to the my images array length. So if the length of this array is 4, the cards I have 4. The issue is I can't display images, I imported them to my project. Main code is in the main page component. Also, I have a component called Author Card. In it, I have a React component, that receives name and image as the props and put them in the card Html block.
Here is my main page component code:
import React from 'react';
import AuthorCard from "./MainPageComponents/AuthorCard";
import BBC_Logo from '../assets/images/BBC_Logo.png';
import FOX_Logo from '../assets/images/FOX_Logo.png';
import CNN_Logo from '../assets/images/CNN_logo.png';
import ForbesLogo from '../assets/images/forbes-logo.png';
function MainPage(props) {
const channels = [
{
name: 'BBC',
index: 1
},
{
name: 'FOX',
index: 2
},
{
name: 'CNN',
index: 3
},
{
name: 'FORBES',
index: 4
},
];
const logos = [
<BBC_Logo key={1} />,
<FOX_Logo key={2}/>,
<CNN_Logo key={3}/>,
<ForbesLogo key={4}/>
];
return (
<div className="main-page">
<div className="main-page_container">
<section className="main-page_channels">
{channels.map( (channel) => {
logos.map( (logo) => {
return <AuthorCard name={channel.name} img={logo} />
})
})}
</section>
</div>
</div>
);
}
export default MainPage;
Here is my Author Card component code:
import React from 'react';
function AuthorCard(props) {
return (
<div className="author-card">
<div className="author-img">
{props.img}
</div>
<div className="author-name">
{props.name}
</div>
</div>
);
}
export default AuthorCard;
Please, help!
I would handle this a bit differently. First thing the way you import your logos is not imported as a component. Rather you get the path/src of the image which you can then use in a component. Read more about that here: https://create-react-app.dev/docs/adding-images-fonts-and-files/
So the way I would do this is to put the logo img src into your channels array and then pass that img src to the AuthorCard component. Then in the AuthorCard component your use a component to render the image. Like this:
import React from "react";
import BBC_Logo from "../assets/images/BBC_Logo.png";
import FOX_Logo from "../assets/images/FOX_Logo.png";
import CNN_Logo from "../assets/images/CNN_logo.png";
import ForbesLogo from "../assets/images/forbes-logo.png";
export default function App() {
return (
<div className="App">
<MainPage />
</div>
);
}
const channels = [
{
name: "BBC",
index: 1,
img: BBC_Logo
},
{
name: "FOX",
index: 2,
img: FOX_Logo
},
{
name: "CNN",
index: 3,
img: CNN_Logo
},
{
name: "FORBES",
index: 4,
img: ForbesLogo
}
];
function MainPage(props) {
return (
<div className="main-page">
<div className="main-page_container">
<section className="main-page_channels">
{channels.map((channel) => {
return <AuthorCard name={channel.name} img={channel.img} />;
})}
</section>
</div>
</div>
);
}
function AuthorCard(props) {
return (
<div className="author-card">
<div className="author-img">
<img src={props.img} alt="author card" />
</div>
<div className="author-name">{props.name}</div>
</div>
);
}
Here, we are using the map function to iterate over the channels array and render an AuthorCard component for each channel. We pass the name property to the AuthorCard component, as well as the corresponding logo from the logos array.
Note that we are also passing a key prop to the AuthorCard component to help React identify each component uniquely. In this case, we're using the index property of each channel object.

How to .Map over different props that are passed into a component?

I'm new to React but hopefully someone can help!
So I've just created a component that takes in a value (via prop) and then .maps over that value creating an Image slider. The props are all an array of objects that contain different values such as :
const Songs = [
{
artist: 'Artist Name',
song: 'Song Name',
lenght: '2:36',
poster: 'images/....jpg'
},
{
artist: 'Artist Name',
song: 'Song Name',
lenght: '2:36',
poster: 'images/....jpg'
},
]
I have been making the same component over and over again because I don't know how to make the 'prop'.map value dynamic. Essentially I don't know how to change the value before the .map each different prop.
Here's an example. I want to make 'Songs'.map dynamic so the new props can replace that so they can also be mapped. Maybe there's another way. Hopefully some can help.
import React from 'react';
import { FaCaretDown } from 'react-icons/fa';
function ImageSlider({Songs, KidsMovies, Movies, TvShows}) {
return (
<>
{Songs.map((image, index) => (
<div className="movie-card">
<img src={'https://image.tmdb.org/t/p/w500' + image.poster_path}
className='movie-img' />
<h5 className='movie-card-desc'>{image.original_title}</h5>
<p className='movie-card-overview'>{movie.overview}</p>
</div>
))}
</>
);
}
export default ImageSlider;
Given your example,
I feel like all you need is render ImageSlides for each array
function ImageSlider({ items }) {
return (
<>
{items.map((item, idx) => (
<div ... key={idx}> // be careful to not forget to put a key when you map components
...
</div>
))}
</>
);
}
When rendering your component
function OtherComponent({ songs, kidsMovies, movies, tvShows }) {
return (
<div>
<ImageSlider items={songs} />
<ImageSlider items={kidsMovies} />
<ImageSlider items={movies} />
<ImageSlider items={tvShows} />
</div>
);
}

How can I limit or specify imported data in React using mapping?

Making my first steps in React with a single-page-application, I want to import a static set of personal data such as:
{
id: '1',
link: 'john-doe',
name: 'John Doe',
title: 'Head of Business Development,
bio: 'Advises major banks and health insurers on topics including strategy, risk management, and operations effectiveness'
},
{
id: '2',
link: 'jane-doe',
name: 'Jane Doe',
title: 'Operations Director',
bio: 'works with retail and consumer-goods companies to guide growth, commercial and operational transformations'},
And pass them into a component using the map function:
{TeamData.map((item, index) => {
return (
<div>
<h1 className="text-3xl xs:text-2xl md:text-3xl lg:text-5xl xl:text-6xl mb-5">{item.name}</h1>
<p className="text-xl leading-10 uppercase mb-5 text-gray-700">{item.title}</p>
<p className="text-xl leading-10 mb-5">{item.bio}</p>
</div>
);
})}
The component containing the mapping function is supposed to be placed on individual pages, each one for a specific team member. Running the mapping function above results in every data entry of name, title and bio from the data set being passed into the component, but I want to limit the import to a specific set, such as the only the set with the id '2'.
How can I limit or specify the data to be imported into the component?
{TeamData.slice(0, limit).map((item, index) => {
return (
<div>
<h1 className="text-3xl xs:text-2xl md:text-3xl lg:text-5xl xl:text-6xl mb-5">{item.name}</h1>
<p className="text-xl leading-10 uppercase mb-5 text-gray-700">{item.title}</p>
<p className="text-xl leading-10 mb-5">{item.bio}</p>
</div>
);
})}
Make the component so it can take a specific ID based on the place where you use it (Or name). Then filter your data based on that ID (or name) and continue mapping like before.
export default function MyComponent({id}){
TeamData.filter(team => team.id === id).map((item, index) => {
return (
<div>
<h1 className="text-3xl xs:text-2xl md:text-3xl lg:text-5xl xl:text-6xl mb-5">{item.name}</h1>
<p className="text-xl leading-10 uppercase mb-5 text-gray-700">{item.title}</p>
<p className="text-xl leading-10 mb-5">{item.bio}</p>
</div>
);
})
}
Depending on your app set up you could use something like react-router to switch between pages, or you could use state to identify which person from the list has been clicked on.
This example uses state.
const { useState } = React;
function Example({ data }) {
// Add the data to the state
const [state, setState] = useState(data);
// Add a new state that captures the person id
const [personId, setPersonId] = useState(null);
// When a person's name is clicked on set the person id
function handleClick(e) {
setPersonId(Number(e.target.dataset.id));
}
// When the reset button is clicked go back to the list
function reset() {
setPersonId(null);
}
// If personId state is null print out all the names
if (!personId) {
return state.map(obj => {
return (
<div
key={obj.id}
data-id={obj.id}
onClick={handleClick}
className="name"
>{obj.name}</div>
);
});
}
// Otherwise print out the person's details
const person = state.find(obj => obj.id === personId);
return (
<div>
<div>{person.name}</div>
<button className="reset" onClick={reset}>Reset</button>
</div>
);
};
const data = [{ id: 1, name: 'Bob' }, { id: 2, name: 'Sam' }, { id: 3, name: 'Claire' }];
// Render it
ReactDOM.render(
<Example data={data} />,
document.getElementById("react")
);
.name:hover { background-color: #efefef; cursor: pointer; }
.reset { margin-top: 1em; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

How do you display a filtered list based on a state created with use state?

I have some code in codesandbox that is made up of 4 divs, 2 with the category "Book" and 2 with the category "Article". Some buttons at the top should trigger if all the divs should be displayed, only the books, or only the articles. All the buttons show every div currently, so the page doesn't change and it looks like the state stays the same
Here is the code which is on the sandbox
App.js
import React, { useState } from "react";
/* import Container from './design/Container' */
import Test from "./Test";
const posts = [
{
title: "React Hooks",
content: "The greatest thing since sliced bread!",
category: "Book"
},
{
title: "Using React Fragments",
content: "Keeping the DOM tree clean!",
category: "Article"
},
{
title: "Angular Hooks",
content: "The greatest thing since sliced bread!",
category: "Book"
},
{
title: "Angular Fragments",
content: "Keeping the DOM tree clean!",
category: "Article"
}
];
export default function App() {
const [productItems, setProductItems] = useState(posts);
function handleButton(e) {
console.log(e.target.value);
if (e.target.value === "All") {
setProductItems(posts);
} else {
setProductItems(
posts.filter((p, i) => <div key={i}>p.category === e.target.value</div>)
);
}
setProductItems(posts);
console.log(productItems);
}
return (
<div>
<Test posts={productItems} handleButton={handleButton} />
</div>
);
}
Test.js
import React from "react";
function Post({ p,title, content, category }) {
return (
<React.Fragment>
<div>
<h3>{p.title}</h3>
<div>{p.content}</div>
<br />
<i>
in <b>{p.category}</b>
</i>
</div>
</React.Fragment>
);
}
export default function Test({handleButton, posts = [] }) {
return (
<React.Fragment>
<div>
<button value="All" onClick={handleButton}>
All
</button>
<button value="Book" onClick={handleButton}>
Book
</button>
<button value="Article" onClick={handleButton}>
Article
</button>
</div>
<div>
{posts.map((p) => {
return <Post key={p.title} p={p} />;
})}
</div>
</React.Fragment>
);
}
style.scss
.App {
font-family: sans-serif;
text-align: center;
}
You had a few things wrong, one was that you handleButton required an argument but you weren't passing one to it. You need to call it like onClick={(e) => handleButton(e)} another was that you set the state of product items again after your if statement. You had already set it to the filtered value, but then you overwrote it with the unfiltered value like setProductItems(posts); so you have to remove this line. Another was that your filter function didn't really make sense. I would look it up and learn more about it. It takes a function that returns a boolean; it doesn't return a div.
SOLUTION
(sandbox)
App.js
import React, { useState } from "react";
import Test from "./Test";
const posts = [
{
title: "React Hooks",
content: "The greatest thing since sliced bread!",
category: "Book"
},
{
title: "Using React Fragments",
content: "Keeping the DOM tree clean!",
category: "Article"
},
{
title: "Angular Hooks",
content: "The greatest thing since sliced bread!",
category: "Book"
},
{
title: "Angular Fragments",
content: "Keeping the DOM tree clean!",
category: "Article"
}
];
export default function App() {
const [productItems, setProductItems] = useState(posts);
function handleButton(e) {
console.log(e.target.value);
if (e.target.value === "All") {
setProductItems(posts);
} else {
setProductItems(posts.filter((p) => p.category === e.target.value));
}
console.log(productItems);
}
return (
<div>
<Test posts={productItems} handleButton={handleButton} />
</div>
);
}
Test.js
import React from "react";
const Post = ({ pa }) => {
return (
<React.Fragment>
<div>
<h3>{pa.title}</h3>
<div>{pa.content}</div>
<i>
in <b>{pa.category}</b>
</i>
</div>
</React.Fragment>
);
};
export default ({ posts = [], handleButton }) => (
<>
<div>
<button value="All" onClick={(e) => handleButton(e)}>
All
</button>
<button value="Book" onClick={(e) => handleButton(e)}>
Book
</button>
<button value="Article" onClick={(e) => handleButton(e)}>
Article
</button>
</div>
<div>
{posts.map((pa, i) => (
<Post key={i} pa={pa} />
))}
</div>
</>
);

ReactJs Accordion Automatic Close Mechanism

I'm currently working on an accordion component in react version 16.3.2, that receives props from another component and displays the accordion accordingly. Unfortunately I cannot use hooks.
This works pretty smoothly, what I want to implement now is a way so that only one accordion can be opened at the same time on the same page. So, once you open one accordion (while another is already opened) it should automatically close the already opened one.
I have an Id (string which describes the current section, e.g 'contact', 'info', etc.) and the state of an accordion gets saved in the state (set to true when you toggle the accordion).
I'm not quite sure on how I could implement this mechanism and am looking for tips on how I could solve this in a smart way. Any pointers?
example:
https://codesandbox.io/s/reactjs-accordion-automatic-close-mechanism-6dys1
(I didn't add all of the styling, animations since this is more about functionality)
You could do something like this, using the state hook in the App component
export default function App() {
const items = [
{ id: 1, title: 'First Accordion', content: 'Hello' },
{ id: 2, title: 'Click me', content: 'Hello 2' },
{ id: 3, title: 'Third Accordion Accordion', content: 'Hello 3' },
]
const [selectedItem, setSelectedItem] = useState(1)
const handleClick = id => {
setSelectedItem(id)
}
return (
<div className="App">
{items.map(x => {
return (
<Accordion
key={x.id}
id={x.id}
title={x.title}
open={x.id === selectedItem}
onClick={handleClick}
>
<p>{x.title}</p>
</Accordion>
)
})}
</div>
);
}
Then your accordion component is a bit simpler
class Accordion extends React.Component {
accToggle() {
this.props.onClick(this.props.id);
}
sectionClasses() {
let classes = "accordion";
classes += this.props.open ? " sec-on" : "";
classes += "sec-underway";
return classes.trim();
}
render() {
return (
<section className={this.sectionClasses()} id={this.props.id}>
<div className="acc-title" onClick={this.accToggle.bind(this)}>
<h3 className="acc-text">{this.props.title}</h3>
<div className="acc-nav">
<span className="acc-toggle" />
</div>
</div>
<div className="acc-content">{this.props.children}</div>
</section>
);
}
}
Accordion.defaultProps = {
open: false
};
Accordion.propTypes = {
id: PropTypes.number.isRequired,
children: PropTypes.any,
onFocus: PropTypes.func,
progress: PropTypes.oneOfType([
PropTypes.number,
PropTypes.string,
PropTypes.bool
]),
title: PropTypes.string,
open: PropTypes.bool
};
export default Accordion;
The accordion calls a function on the app component, which updates the state and the display logic is passed down in the props
You can find solution for your problem in the following codesandbox
https://codesandbox.io/s/reactjs-accordion-automatic-close-mechanism-yejc0
Change prop names as it fits your code base, but the logic is solid

Categories

Resources