I tried to create a component 'Card' and use it like a container.
the code work well without 'card'.
when I tried to add it the 'Card.css' and expense-item in ExpenseItem.css doesn't work
this is 'ExpenseItem.js':
import Card from './Card';
import ExpenseDate from './ExpenseDate';
import './ExpenseItem.css';
function ExpenseItem(props) {
return (
<Card className='expense-item' >
<ExpenseDate date={props.date} />
<div className='expense-item__description'>
<h2 >{props.title}</h2>
<div className='expense-item__price'>{props.amount} Da </div>
</div>
</Card>
);
}
export default ExpenseItem;
this is 'Card.js':
import './Card.css';
function Card(props){
const classes ='card'+props.className;
return <div className={classes}> {props.children} </div>;
}
export default Card;
and this is 'Card.css':
.card {
border-radius: 12px;
box-shadow: 0 1px 8px rgba(0, 0, 0, 0.25);
}
and finally this is 'ExpenseItem.css':
.expense-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.5rem;
margin: 1rem 0;
background-color: #ff0000;
}
You need a space between card and the class name in the classes variable. Because there is no space, the className attribute in the card component is just cardexpense-item.
This is how it should look:
const classes = 'card '+props.className;
By the way, you can also use ES6 template literals feature (it's up to you but I prefer them more):
const classes = `card ${props.className}`;
Related
I would like to create one component that included the dot between 2 elements. the code I have is like following, However, I tried to use span element then create css so I can display . between 2 span. but react does not generate the dot between 2 span. I also tried to use div and then dot did display but format of 2 element does not align at center
//html
import "./styles.css";
export default function App() {
return (
<div className="panel-section">
<div className="panel-header">
<div className="panel-title">
{/** use div format is not correct */}
<div>May 1st 5:31PM</div>
<div className="panel-dot"></div>
<div>Google</div>
{/** dot is not generated
<span>May 1st 5:31PM</span>
<span className="panel-dot"></span>
<span>Google</span>
*/}
</div>
</div>
</div>
);
}
//css
.panel {
width: 600px;
height: 500px;
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
left: 0.5%;
right: 33.44%;
}
.panel-title {
padding: 8px;
color: #ffffff;
background-color: #3aac6f;
}
.panel-dot {
width: 4px;
height: 4px;
background: #3aac6f;
align-self: center;
}
codepen:
You can try this :
App.js
import React from 'react';
import './style.css';
export default function App() {
return (
<div className="panel-section">
<div className="panel-header">
<div className="panel-title">
<span>May 1st 5:31PM</span>
<span>Google</span>
</div>
</div>
</div>
);
}
style.css
.panel-title span:first-of-type::after {
content: '.';
}
Demo : Stackblitz
OR
App.js
import React from 'react';
import './style.css';
export default function App() {
return (
<div className="panel-section">
<div className="panel-header">
<div className="panel-title">
<span>May 1st 5:31PM</span>
<span>{"."}</span>
<span>Google</span>
</div>
</div>
</div>
);
}
I have a parent component that gets data from an API end point using fetch. This data displays like it should. The parent component passes an element of an array of objects to the child component. In the child component, when I do a console log I can see the state when it's undefined and when the state is set. The issue that I am having is when I try to access a key of the state (i.e. ticket.title) I get an error saying that ticket is undefined. Any help with would be great.
TicketList
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import TicketDetails from "./TicketDetails"
export default function TicketList() {
const [tickets, updateTickets] = useState([])
const [ticketIndex, updateticketIndex] = useState("0")
useEffect(() => {
async function fetchTickets() {
const response = await fetch("/api/v1/tickets")
const json = await response.json()
updateTickets(json.data)
}
fetchTickets()
}, [])
return (
<Wrapper>
< div >
<TableTitle>
<h3>Tickets</h3>
<button type="submit">Create A Ticket</button>
</TableTitle>
{
tickets.map((ticket, index) => (
<ListInfo key={ticket._id} onClick={() => updateticketIndex(index)}>
<Left>
<p>{ticket.project}</p>
<p>{ticket.title}</p>
<p>{ticket.description}</p>
</Left>
<Right>
<p>{ticket.ticketType}</p>
<p>{ticket.ticketStatus}</p>
<p>{ticket.ticketPriority}</p>
</Right>
</ListInfo>
))
}
</div>
<TicketDetails key={tickets._id} data={tickets[ticketIndex]} />
</Wrapper>
);
}
const Wrapper = styled.div`
display: flex;
background: white;
grid-area: ticketarea;
height: calc(100vh - 4.25rem);
`
const ListInfo = styled.div`
display: flex;
justify-content: space-between;
width: 100%;
padding: .5rem .75rem;
border-bottom: solid 1px #ccc;
`;
const Left = styled.div`
display: flex;
flex: 2;
flex-direction: column;
p {
padding: .25rem;
}
`;
const Right = styled.div`
display: flex;
flex: 1;
flex-direction: column;
align-items: end;
width: 500px;
p {
padding: .25rem;
}
`;
const TableTitle = styled.div`
display: flex;
justify-content: space-between;
padding: 1rem 1rem;
border-bottom: solid 1px #ccc;
button {
padding: .5rem;
}
`;
TicketDetails
import React, { useEffect, useState } from 'react'
// import TicketInfo from './TicketInfo'
import TicketNotes from "./TicketNotes"
import styled from "styled-components"
export default function TicketDetail(data) {
const [ticket, setTicket] = useState(data)
useEffect(() => {
setTicket(data)
}, [data])
console.log(ticket.data)
return (
<Main>
<TicketInfo key={ticket._id}>
<h2>{ticket.title}</h2>
<Info>
<div>
<InfoItem>
<p>Project</p>
<p>{ticket.project}</p>
</InfoItem>
<InfoItem>
<p>Assigned Dev</p>
<p>{ticket.assignedDev}</p>
</InfoItem>
<InfoItem>
<p>Created By</p>
<p>{ticket.submitter}</p>
</InfoItem>
</div>
<div>
<InfoItem>
<p>Type</p>
<p>{ticket.ticketType}</p>
</InfoItem>
<InfoItem>
<p>Status</p>
<p>{ticket.ticketStatus}</p>
</InfoItem>
<InfoItem>
<p>Priority</p>
<p>{ticket.ticketPriority}</p>
</InfoItem>
</div>
</Info>
<Description>{ticket.description}</Description>
</TicketInfo>
<TicketNotes />
<TicketComment>
<textarea name="" id="" cols="30" rows="10" />
<button type="submit">Submit</button>
</TicketComment>
</Main>
)
}
const TicketInfo = styled.div`
margin: .5rem;
h2{
padding: 0.5rem 0;
}
`;
const Description = styled.p`
padding-top: .5rem;
`;
const Info = styled.div`
display: flex;
justify-content: space-between;
border-bottom: solid 1px #ddd;
`;
const InfoItem = styled.section`
margin: .5rem 0;
p:nth-child(1) {
text-transform: uppercase;
color: #ABB1B6;
font-weight: 500;
padding-bottom: .25rem;
}
`;
const Main = styled.div`
background: white;
`
const TicketComment = styled.div`
display: flex;
flex-direction: column;
width: 40rem;
margin: 0 auto ;
input[type=text] {
height: 5rem;
border: solid 1px black;
}
textarea {
border: solid 1px black;
}
button {
margin-top: .5rem;
padding: .5rem;
width: 6rem;
}
`;
There are a few issues here, let's tackle them in order.
Tickets are undefined
When TicketList is mounted, it fetches tickets. When it renders, it immediately renders TicketDetail. The tickets fetch request won't have finished so tickets is undefined. This is why TicketDetail errors out. The solution is to prevent rendering TicketDetail until the tickets are available. You have a few options.
A bare bones approach is to just prevent rendering until the data is available:
{ !!tickets.length && <TicketDetails key={tickets._id} data={tickets[ticketIndex]} />
This uses how logical operators work in JS. In JS falsey && expression returns falsey, and true && expression returns expression. In this case, we turn ticket.length into a boolean. If it is 0 (i.e. not loaded, therefore false), we return false, which React simply discards. If it is greater than 0 (i.e. loaded, therefore true), we render the component.
This doesn't really result in a positive UX though. Ideally this is solved by showing some kind of Loading spinner or somesuch:
{
!!tickets.length
? <TicketDetails . . . />
: <LoadingSpinner />
}
Child data access
In TicketDetail it seems like you meant to destructure data. Currently you are taking the entire prop object and setting it to ticket. Fixing this should resolve the other half of the issue.
Paradigms
You didn't specifically ask for this, but I’d like to back up and ask why you are putting this prop into state? Typically this only done when performing some kind of ephemeral edit, such as pre-populating a form for editing. In your case it looks like you just want to render the ticket details. This is an anti-pattern, putting it into state just adds more code, it doesn’t help you in any way. The convention in React is to just render props directly, state isn't needed.
In my Class component Field.jsx render(), I'm expanding my <Position> component using <Flipper>, (an abstracted flip animation), like so:
import { Flipper, Flipped } from 'react-flip-toolkit'
import { Position } from "./Position";
import "./css/Position.css";
class Field extends Component {
constructor(props) {
super(props);
this.state = {
fullScreen: false,
};
}
toggleFullScreen() {
this.setState({ fullScreen: !this.state.fullScreen });
}
...
render() {
const { players } = this.props;
const { fullScreen } = this.state;
if(players){
return (
<div className="back">
<div className="field-wrapper" >
<Output output={this.props.strategy} />
<Flipper flipKey={fullScreen}>
<Flipped flipId="player">
<div className="field-row">
{this.getPlayersByPosition(players, 5).map((player,i) => (
<Position
key={i}
className={fullScreen ? "full-screen-player" : "player"}
getPositionData={this.getPositionData}
toggleFullScreen={this.toggleFullScreen.bind(this)}
>{player.name}</Position>
))}
</div>
</Flipped>
</Flipper>
</div>
</div>
);
}else{
return null}
}
When I render it, I get clickable items from the mapped function getPlayersByPosition(), like so:
And if I click on each item, it expands to a div with player name:
Which is passed as props.children at component <div>
Position.jsx
import React from "react";
import "./css/Position.css";
export const Position = props => (
<div
className={props.className}
onClick={() => {
props.getPositionData(props.children);
props.toggleFullScreen();
console.log(props.getPositionData(props.children))
}}
>
{props.children}
</div>
);
getPositionData(), however, returns an object with many items on its turn, as seen by console above:
{matches: 7, mean: 6.15, price: 9.46, value: 0.67, G: 3, …}
QUESTION:
How do I pass and print theses other props keys and values on the expanded purple div as text?, so as to end with:
Patrick de Paula
matches: 7
mean: 6.15
price:9.46
....
NOTE:
Position.css
.position-wrapper {
height: 4em;
display: flex;
justify-content: center;
align-items: center;
font-weight: lighter;
font-size: 1.4em;
color: #888888;
flex: 1;
/*outline: 1px solid #888888;*/
}
.player {
height: 4em;
width: 4em;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
font-weight: lighter;
font-size: 1.4em;
/*background-color: #66CD00;*/
color: #ffffff;
}
.full-screen-player {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
cursor: pointer;
background-image: linear-gradient(
45deg,
rgb(121, 113, 234),
rgb(97, 71, 182)
);
}
Looks like the props are all set & ready to be print as seen on your console. You can access them via props.getPositionData(props.children).property_name_here or destructure them
export const Position = props => {
const { matches, mean, price } = props.getPositionData(props.children);
return (
<div
className={props.className}
onClick={() => {
props.getPositionData(props.children);
props.toggleFullScreen();
console.log(props.getPositionData(props.children))
}}
>
<p>Name: {props.children}</p>
<p>Matches: {matches}</p>
<p>Mean: {mean}</p>
<p>Price: {price}</p>
</div>
)
}
Regarding the issue on the fullScreen prop (see comments section):
Is there a way to print them ONLY after toggleFullScreen()
Since you already have a state on the Field component which holds your fullScreen value, on your Field component, you need to pass the fullScreen prop as well to the Position component. e.g., fullScreen={this.state.fullScreen}. Back on Position component, have some condition statements when you are rendering.
Example:
<>
{props.fullScreen &&
<p>Name: {props.children}</p>
}
</>
Im new to javascript and trying to figure this out. I am trying to have the div structure in renderNewCard() appear on the page everytime you click the button. The button seems to work when i call a function with just an alert message, but it does nothing when i call this method and try to output the div structure. I attached a picture of what the div structure looks like and what should be added when clicking the button. In the render, don't worry about the lander and authentication methods for those work fine. Im having issues with the button producing the output i want from calling the function with the div structure. I might be missing something, but not entirely sure. Any help/advice is appreciated.
.Home .newObjects {
height: 130px;
padding-top: 81px;
}
.Home .newObjects button {
border-width: 2px;
border-color: rgb(98, 98, 98);
border-style: solid;
border-radius: 6px;
background: rgb(255, 255, 255);
box-shadow: 0px 0px 9px 0px rgba(0, 0, 0, 0.18);
width: 72px;
height: 100%;
margin-left: 72%;
font-weight: bold;
}
.Home .newObjects button:focus {
outline: none;
}
.card {
min-height: 310px;
}
.scroll-box {
overflow-y: scroll;
height: 310px;
padding: 1rem;
}
.card-border{
border-style: solid;
border-width: 2px;
margin-top: 50px;
box-shadow: 0px 0px 9px 0px rgba(0, 0, 0, 0.18);
}
import React, {Component} from "react";
import "./Home.css";
import {ControlLabel, FormControl, FormGroup} from "react-bootstrap";
export default class Home extends Component {
renderNewObjectsButton() {
return (
<div className="newObjects">
<button onClick={()=>this.renderNewCard()}>New</button>
</div>
)
}
render() {
return (
<div className="Home">
{this.props.isAuthenticated ? [this.renderNewObjectsButton()]
: this.renderLander() }
</div>
);
}
renderNewCard(){
return(
<div className="row" id="container">
<div className="card-border" >
<div className="card">
<div className="card-body">
Customer
</div>
<div className="card-body">
Vehicle
</div>
<div className="card-body">
Transaction
</div>
</div>
</div>
</div>
);
}
}
enter image description here
<button onClick={() => { this.setState({ show: true })}}>{this.state.show &&this.renderNewCard()}</button>
Go through this https://medium.com/#johnwolfe820/rendering-components-in-onclick-events-in-react-bc0d7b54e1cd link. It is just setting the value to rendered on the basis of conditions.
Hope it will serve your purpose.
call your home object inside button onclick
you have somthing like
export var home = new Home()
so use this like
<button onClick={()=>home.renderNewCard()}>New</button>
Each react component has one render method and will only render what is returned by that method. And the way to influence the render method is by changing the props or the state of the component.
What you need is a variable stored in the state of the component like:
import React, {Component} from "react";
import "./Home.css";
import {ControlLabel, FormControl, FormGroup} from "react-bootstrap";
export default class NewObjectsButton extends Component {
render() {
return (
<div className="newObjects">
<button onClick={this.props.renderNewCard}>New</button>
</div>
)
}
}
export default class NewCard extends Component {
render() {
return(
<div className="row" id="container">
<div className="card-border" >
<div className="card">
<div className="card-body">
Customer
</div>
<div className="card-body">
Vehicle
</div>
<div className="card-body">
Transaction
</div>
</div>
</div>
</div>
);
}
}
export default class Home extends Component {
state = {
shouldRenderNewCard: false,
};
renderNewCard() {
this.setState({ shouldRenderNewCard: true });
};
render() {
return (
<div className="Home">
{this.props.isAuthenticated ? <NewObjectsButton renderNewCard={this.renderNewCard} />
: this.renderLander() }
{this.state.shouldRenderNewCard ? <NewCard /> : null}
</div>
);
}
}
I am in a project where we use very different headings.
I am trying to unify them into one component
I am trying to decouple semantics (h1, h2, ...) from looks
Here is what the currently looks like (work in progress)
import * as React from 'react';
import './Heading.css';
import { MarkupContent } from 'app-types';
import HeadingElement from './HeadingElement';
interface HeadingProps {
type: 'fullwidth' | 'emphasis';
children: MarkupContent;
element: 'h1' | 'h2';
}
function Heading(props: HeadingProps) {
switch (props.type) {
case 'fullwidth':
return (
<div className="big-heading-container">
<div className="big-heading-section">
<HeadingElement element={props.element} classes="big-heading-text">
{props.children}
</HeadingElement>
</div>
</div>
);
case 'emphasis':
return (
<h2 className="heading--emphasized">
{props.children}
</h2>
);
default:
return (
<></>
);
}
}
export default Heading;
import * as React from 'react';
import { MarkupContent } from 'app-types';
interface HeadingElementProps {
element: 'h1' | 'h2';
classes: string;
children: MarkupContent;
}
function HeadingElement(props: HeadingElementProps) {
switch (props.element) {
case 'h1':
return (
<h1 className={props.classes}>{props.children}</h1>
);
case 'h2':
return (
<h2 className={props.classes}>{props.children}</h2>
);
default:
return (
<></>
);
}
}
export default HeadingElement;
#import "../../parameters.scss";
.big-heading {
&-container {
padding: 90px 25px 0 25px;
background-image: url("../../images/heading-background.png");
border-bottom: 1px solid $green;
}
&-section {
max-width: $max-width;
margin: 0 auto 0 auto;
display: flex;
}
&-text {
font-size: 1.5rem;
text-transform: uppercase;
border-bottom: 4px solid $green;
padding: 0 0 15px 0;
display: inline;
}
}
.heading--emphasized {
font-size: 1.7rem;
line-height: 2.0rem;
font-weight: bold;
text-transform: uppercase;
display: inline;
border-top: solid 4px #94d500;
padding-top: 10px;
padding-right: 30px;
}
I am particularly interested in the switch statement where I return an or element with passed on props.children.
Is this a good approach or is there a better way to switch which element is rendered based on a prop?
Looks fine to me. The same approach is also used for changing states to render something different.
If props.element can only be 'h1' or 'h2' (two possible values) I'd rather use ternary conditional statements instead of a switch statement.
Is something like this looks better?
function HeadingElement(props: HeadingElementProps) {
return props.element === 'h1' ? <h1 className={props.classes}>{props.children}</h1> : <h2 className={props.classes}>{props.children}</h2>
}