I am trying to make a React component hidden by clicking on it but all I see online are explanations about event handlers on buttons and the like.
I'm using Next.js (but I don't think these means much for this).
This is my component:
import styles from './styles/popup.module.scss';
import React, { Component } from "react";
export default function Popup() {
return (
<div className={styles.popup}>
<div className={styles.popupInner}>
<h1>Temporary Closure</h1>
<p>
Following the Australian government’s directive to keep our nation safe and limit the spread of Coronavirus (Covid-19), it is with great sadness that we advise that SS will be temporarily closed, effective 23<sup>rd</sup> March 2020
</p>
</div>
</div>
)
}
Try setting a state on click of your component. Below code should work.
import styles from './styles/popup.module.scss';
import React, { Component } from "react";
export default function Popup() {
const [visible, setVisible] = React.useState(true);
if(!visible) return null;
return (
<div className={styles.popup} onClick={() => setVisible(false)}>
<div className={styles.popupInner}>
<h1>Temporary Closure</h1>
<p>
Following the Australian government’s directive to keep our nation safe and limit the spread of Coronavirus (Covid-19), it is with great sadness that we advise that sydney sauna will be temporarily closed, effective 23<sup>rd</sup> March 2020
</p>
<div className={styles.buttonContainer}><button className={styles.button}>Okay</button></div>
</div>
</div>
)
}
Hope it helps.
You could use a state property which tells you whether you should hide the component or not.
Based on that state, conditionally render another css class to the component you want to hide, using the classnames package (you will need to preinstall it npm install --save classnames)
import React, {useState} from 'react';
import classes from './Component.module.css';
import classNames from 'classnames';
const Component = props => {
const [show, setShow] = useState(true);
return (
<div className={classes.Component} onClick={() => setShow(!show)}>
<div
className={classNames( {
[classes.Show]: true,
[classes.Disappear]: !show
})}
>
{props.children}
</div>
</div>
);
};
export default Component;
In the Disappear css class, you can use whatever css properties you need to make your component disappear in a more elegant way, such as display: none; or visibility: hidden; (including transitions)
Of course, if what you are looking for is just not rendering the component at all, the standard "wrapping the div in an if statement" shown in the other answers is a perfectly valid solution.
You need to create a state variable which will determine to show popup or not.
You can achieve it by using useState hook.
import styles from './styles/popup.module.scss';
import React, { Component , useState } from "react";
export default function Popup() {
const [isPopupVisible,setPopupVisibility] = useState(true);
return (
<div className={styles.popup}>
{ isPopupVisible && (<div className={styles.popupInner}>
<h1>Temporary Closure</h1>
<p>
Following the Australian government’s directive to keep our nation safe and limit the spread of Coronavirus (Covid-19), it is with great sadness that we advise that SS will be temporarily closed, effective 23<sup>rd</sup> March 2020
</p>
<div className={styles.buttonContainer}><button className={styles.button} onClick={setPopupVisibility(false)}>Okay</button></div>
</div>)}
</div>
)
}
Related
I have react component which is a button and I render this component three times. I want to add some CSS on the second component but I don't know how. I tried to add some class names, but then I can't figure it out where to put this style in the CSS.
I can change css in element.style in dev tools but can't in project.
import './App.css';
import './flow.css';
import './neonButton.css';
import GlowBox from './GlowBox';
import NavBar from './NavBar';
function App() {
return (
<div>
<div className='divBut'>
<NavBar></NavBar>, <NavBar className='drugi'></NavBar>,<NavBar></NavBar>
</div>
<GlowBox></GlowBox>
</div>
);
}
export default App;
import styled from 'styled-components';
const NavBar = (props) => {
return (
<div>
<Container>
<a class='neon'>Neon</a>
</Container>
</div>
);
};
const Container = styled.div`
background-color: transparent;
`;
export default NavBar;
I try to add props to component
<!-- begin snippet: js hide: false console: true babel: false -->
and then add a type to a component like this
const NavBar = (type) => {
return (
<div>
<Container>
<a class={`neon ${type}`}>Neon</a>
</Container>
</div>
);
};
<NavBar></NavBar>, <NavBar type='drugi'></NavBar>,<NavBar></NavBar>
but nothing is change.
You have props that you don't use, this is a good simple read on How to Pass Props to component, you can adjust this to other needs, this is example...:
import styled from 'styled-components';
const NavBar = ({class}) => {
return (
<div>
<Container>
<a class={class}>Neon</a>
</Container>
</div>
);
};
const Container = styled.div`
background-color: transparent;
`;
export default NavBar;
...
import './App.css';
import './flow.css';
import './neonButton.css';
import GlowBox from './GlowBox';
import NavBar from './NavBar';
function App() {
const NavStyles = {
className1: 'neon',
className2: 'drugi'
};
return (
<div>
<div className='divBut'>
<NavBar class={NavStyles.className1}></NavBar>, <NavBar class={NavStyles.className2}></NavBar>,<NavBar class={NavStyles.className1}></NavBar>
</div>
<GlowBox></GlowBox>
</div>
);
}
export default App;
Edit: Given that you have edited your question I have new information for you.
1.) You can't use the reserved word class in React, because class means something different in Javascript than it does in html. You need to replace all instances of class with className.
2.) Did you notice how in the devtools on your button it says the className says: neon [object object]?
You should use a ternary operator to handle the cases where you don't pass the type prop.
ex.) class={neon ${props?.type !== undefined ? type ''}}
3.) You are trying to apply a className to a component, which does not work. The className attribute can only be applied directly to JSX tags like h1, div, etc. Use a different prop name, then you can use that to decide the elements className.
Having trouble using Create React App to change a background image I feed to my component through props. The docs say use the import syntax. This works but it would mean I have to hard code every background image to each component. Anyway to do this dynamically?
I noticed it won't let me use template literals on the import syntax as well. That would have fixed my issue I think.
import '../css/Avatar.css';
import photo from "../images/joe_exotic.jpg";
const Avatar = (props) => {
return (
<div
style={{backgroundImage: `url("${photo}")`}}
className="avatar">
</div>
)
}
export default Avatar;
P.S: I checked out the other articles on StackOverflow regarding this and they didn't provide much help.
If you wanna avoid this way of doing, you can put your images in the public folder of your React app, et grab them like so :
import '../css/Avatar.css';
const Avatar = (props) => {
return (
<div
style={{backgroundImage: `url("/joe_exotic.jpg")`}}
className="avatar">
</div>
)
}
export default Avatar;
I hope it works for you. good luck.
import '../css/Avatar.css';
import photo from "../images/joe_exotic.jpg";
const Avatar = (props) => {
return (
<div
style={{backgroundImage:url(photo)}}
className="avatar">
</div>
) }
export default Avatar;
I am learning React with the help of a crash course. I was learning about nested components and props where I have some confusion. I was making a small comment section.Like thisHere I have used two components the CommentDetail.js where user's name,image and comment will display and ApprovalCard.js which is for approving the comment made by user(Approve/Reject).CommentDetail here is child component of ApprovalCard here.The instructor told that when we nest the components the parent component receive object in props.And this props contains a property children which we can render.What I am not understanding is when I console.log(props) in ApprovalCard.js children itself is an object inside props.As object can not render in JSX than how {props.children} is working here ?Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import faker from 'faker';
import CommentDetail from './CommentDetail';
import ApprovalCard from './ApprovalCard';
const App = () => {
return (
<div className='ui comments'>
<ApprovalCard>
<CommentDetail author='Maximillian' timesAgo = 'Today at 4:00PM' comment = 'Nice blog post!'
image = {faker.image.avatar()}/>
</ApprovalCard>
<ApprovalCard>
<CommentDetail author='Kishan' timesAgo = 'Today at 1:00AM' comment = 'Touched every important point.'
image = {faker.image.avatar()}/>
</ApprovalCard>
<ApprovalCard>
<CommentDetail author='Punit' timesAgo = 'Today at 6:32PM' comment = 'Far better than any other article I have come across'
image = {faker.image.avatar()}/>
</ApprovalCard>
</div>
);
};
ReactDOM.render(<App/>,document.querySelector('#root'));
CommentDetail.js
import React from 'react';
const CommentDetail = (props)=>
{
console.log(props);
return (
<div className="comment">
<a className='avatar'>
<img alt="avatar" src={props.image}/>
</a>
<div className='content'>
<a className='author'>{props.author}</a>
<div className='metadata'>
<span className='date'>{props.timesAgo}</span>
</div>
<div className='text'>
{props.comment}
</div>
</div>
</div>
);
};
export default CommentDetail;
ApprovalCard.js
import React from 'react';
const ApprovalCard = (props) => {
console.log(props.children);
return (
<div className = "ui card">
<div className="content">{props.children}</div>
<div className="extra content">
<div className="ui two buttons">
<div className="ui basic green button">Approve</div>
<div className="ui basic red button">Reject</div>
</div>
</div>
</div>
);
};
export default ApprovalCard;
Your code is containing the following <ApprovalCard> component which has one component inside which is the <CommentDetail> child:
<ApprovalCard>
<CommentDetail author='Maximillian' timesAgo = 'Today at 4:00PM' comment = 'Nice blog post!' image = {faker.image.avatar()} />
</ApprovalCard>
So technically props.children will be the <CommentDetail> component which can be rendered as JSX in the following statement because it is not just a simple object:
<div className="content">{props.children}</div>
From the Composition vs Inheritance documentation check especially the containment section which states:
Some components don’t know their children ahead of time. This is especially common for components like Sidebar or Dialog that represent generic “boxes”.
We recommend that such components use the special children prop to pass children elements directly into their output.
I hope this helps!
I need to disable PostList component in its initial state.
import React from 'react';
import PostList from './PostList';
const App = () => {
return (
<div className="ui container">
<PostList />
</div>
);
};
export default App;
Whats the best way to disable (and grey out) a component? Possible solutions are to pass a value as props and then apply it to a ui element, However please keep in mind that PostList may have inner nested components as well. Please share an example.
Since you mentioned in a comment that instead of hiding it, you want to grey it instead. I would use the disabled state and style the component. Since PostList could be nested, we don't know what the props are since you did not specify them.
Also, I assuming that you are not using styled-components.
import React, { useState } from "react";
import PostList from "./PostList";
const App = () => {
const [disabled, setDisabled] = useState(true);
return (
<div className="ui container">
<PostList
style={{
opacity: disabled ? 0.25 : 1,
pointerEvents: disabled ? "none" : "initial"
}}
/>
</div>
);
};
export default App;
There are 2 different ways I like to do something like this.
One way you can do it is by using state
this.state = {
showList: false
}
and than something like
return (
{this.state.showList && <PostList />}
)
Another option is to pass the showList in state as a prop, so something like
return(
<PostList show = {this.state.showList} />
)
and than in PostList something like
return props.show && (your component here)
You can also use conditional classNames, so if you want that component shown, you can throw a className and style it how you normally would, but if not, just throw a display: none. I usually save doing that for replacing a navbar with a dropdown button on smaller screens, but it is another option
I render different landing pages based on whether the user is a professor, student, or not logged in. The landing pages are very similar; the only difference is the buttons displayed. I know I can go around this using inline conditions or simple if-else statements. However, I was wondering what the best practices are to implement conditional rendering in this case. I know higher order components (HOCs) can help but I was not sure if they are overkill in this particular case.
To be on the same page, here are the different Landing components that I currently render using if-else statements.
Landing.js (unlogged users):
import React from 'react';
import { withRouter } from 'react-router-dom';
import { compose } from 'recompose';
import { withEither } from '../../helpers/withEither';
import LandingStudent from './LandingStudent';
import LandingProfessor from './LandingProfessor';
import './Landing.css';
const Landing = ({ history }) => {
return(
<div className="header">
<div className="text-box">
<h1 className="header-primary">
<span className="header-primary-main">
QME
</span>
<span className="header-primary-sub">
the best way to ask questions
</span>
</h1>
</div>
</div>
);
};
export default Landing;
LandingProfessor.js
import React from 'react';
import { withRouter } from 'react-router-dom';
import RaisedButton from 'material-ui/RaisedButton';
import './Landing.css';
const LandingProfessor = ({ history }) => {
return(
<div className="header">
<div className="text-box">
<h1 className="header-primary">
<span className="header-primary-main">
QME
</span>
<span className="header-primary-sub">
the best way to ask questions
</span>
</h1>
<RaisedButton
className="btn-animated btn-landing"
label="Create Class"
onClick={() => history.push('/courses/new')}
/>
<RaisedButton
className="btn-animated btn-landing"
label="Dashboard"
onClick={() => history.push('/courses')}
/>
</div>
</div>
);
};
export default withRouter(LandingProfessor);
LandingStudent.js
import React from 'react';
import { withRouter } from 'react-router-dom';
import RaisedButton from 'material-ui/RaisedButton';
import './Landing.css';
const Landing = ({ history }) => {
return(
<div className="header">
<div className="text-box">
<h1 className="header-primary">
<span className="header-primary-main">
QME
</span>
<span className="header-primary-sub">
the best way to ask questions
</span>
</h1>
<RaisedButton
className="btn-animated btn"
label="Join Class"
onClick={() => history.push('/courses/join')}
/>
</div>
</div>
);
};
export default withRouter(Landing);
A 'trick' could be to append a className on the root div for landscape, namely 'student' 'professor' or 'logout' and use css display: none to hide unwanted items in each scenarios
Another approach would be to keep your 3 components but delegate all the rendering to a common 'LandingRenderer' component that would accept boolean properties like 'showJoinClassButton' 'showCreateButtonButton' etc.
Then your 3 components render would look like domething like this
LandingProfessor: (props) => (
<LandingRenderer
showJoinClassButton={false}
showCreateClassButton={true}
...
{...props} />
)
I would opt for composition over inheritance here, meaning create many reusable components and compose your top-level components with those reusable ones rather than make your top-level components inherit from one common component type. If you follow the latter approach, you might end up with a laundry list of props that I argue is questionably better than what you have right now.
To start, you could componentize your header:
Header.js
export default function Header(props) {
return (
<h1 className="header-primary">
{props.children}
</h1>
);
}
Header.Main = function HeaderMain(props) {
return (
<span className="header-primary-main">
{props.children}
</span>
);
};
Header.Sub = function HeaderSub(props) {
return (
<span className="header-primary-sub">
{props.children}
</span>
);
};
and use it in Landing.js:
import Header from './Header.js';
const Landing = ({ history }) => {
return(
<div className="header">
<div className="text-box">
<Header>
<Header.Main>QME</Header.Main>
<Header.Sub>the best way to ask questions</Header.Sub>
</Header>
</div>
</div>
);
}
I don't think hoc in this particular case is an overkill.
I think whenever you can use hoc for better readability and useability, use it.
Using some of recompose hocs (you should install recompose: npm install recompose)
export const renderByConditions = (...conditions) => compose(
...conditions.map(condition =>
branch(condition[0], (condition[1] && renderComponent(condition[1])) || renderNothing, condition[2] && renderComponent(condition[2]))
)
)
You should pass arrays with the signature:
[condition, left (if the condition is true), right (else)]
condition - (ownProps) => youCondition
left - Component | empty
right - Component | empty
when left is empty - if the condition is true, it will render null.
when right is empty - if the condition is not true, it will render the component we wrapped
Then you can use the hoc:
renderByConditions(
[props => props.landing, props => <Landing {...props}/>],
[props => props.proffesor, LandingProfessor],
[props => props.student, LandingStudent],
[Component => Component, DefaultComponent]
)
I would reccommend start using recompose hocs, they are great!