My sliding menu in React does not work? - reactjs

follow the tutorial but apparently does not work as it should, by pressing the button should appear the menu on the right side but it appears in this way, what is wrong?
the MenuContainer class change it to SideBar.js
all classes are inside SideBar.js
import React, { Component } from "react";
class SideBar extends React.Component {
constructor(props) {
super(props);
this.state = { visible: false };
this.handleMouseDown = this.handleMouseDown.bind(this);
this.toggleMenu = this.toggleMenu.bind(this);
}
toggleMenu() {
this.setState({
visible: !this.state.visible
});
}
handleMouseDown(e) {
this.toggleMenu();
console.log("clicked");
e.stopPropagation();
}
render() {
return (
<div>
<MenuButton handleMouseDown={this.handleMouseDown}/>
<Menu handleMouseDown={this.handleMouseDown} menuVisibility={this.state.visible}/>
<div>
<div>
<p>Can you spot the item that doesn't belong?</p>
<ul>
<li>Lorem</li>
<li>Ipsum</li>
<li>Dolor</li>
<li>Sit</li>
<li>Bumblebees</li>
<li>Aenean</li>
<li>Consectetur</li>
</ul>
</div>
</div>
</div>
);
}
}
export default SideBar;
class MenuButton extends React.Component {
render() {
return (
<button className="roundButton"
onMouseDown={this.props.handleMouseDown}></button>
);
}
}
class Menu extends React.Component {
render() {
var visibility = "hide";
if (this.props.menuVisibility) {
visibility = "show";
}
return (
<div className="flyoutMenu"
onMouseDown={this.props.handleMouseDown}
className={visibility}>
<h2>Home</h2>
<h2>About</h2>
<h2>Contact</h2>
<h2>Search</h2>
</div>
);
}
}
and my styles.scss
.roundButton {
background-color: #96D9FF;
margin-bottom: 20px;
width: 50px;
height: 50px;
border-radius: 50%;
border: 10px solid #0065A6;
outline: none;
transition: all .2s cubic-bezier(0, 1.26, .8, 1.28);
}
.roundButton:hover {
background-color: #96D9FF;
cursor: pointer;
border-color: #003557;
transform: scale(1.2, 1.2);
}
.roundButton:active {
border-color: #003557;
background-color: #FFF;
}
.flyoutMenu {
width: 100vw;
height: 100vh;
background-color: #FFE600;
position: fixed;
top: 0;
left: 0;
transition: transform .3s
cubic-bezier(0, .52, 0, 1);
overflow: scroll;
z-index: 1000;
}
.flyoutMenu.hide {
transform: translate3d(-100vw, 0, 0);
}
.flyoutMenu.show {
transform: translate3d(0vw, 0, 0);
overflow: hidden;
}
This is the image of how it is displayed when you click on it.
image

you mutate the state from SideBar component. Sidebar component passes down state to Menu as a prop. When you mutate this state, it should re-render the Menu component with the new value.
Your menu class would look something better like:
class Menu extends React.Component {
render() {
const { menuVisibility } = this.props
return (
<div className="flyoutMenu"
onMouseDown={this.props.handleMouseDown}
className={menuVisibility ? 'show' : 'hide'}>
<h2>Home</h2>
<h2>About</h2>
<h2>Contact</h2>
<h2>Search</h2>
</div>
);
}

Related

react all list items get re-rendered

I have my state structured like this. It's an object with multiple fields inside of it. For certain purposes, I cannot modify the structure of the state. Here's my component which renders the entire List
import React, { Component } from 'react'
import styled from 'styled-components';
import FoodListItem from '../Food-List-Item'
const Wrapper = styled.div`
width: 300px;
max-width: 300px;
`
const Button = styled.button`
width: 300px;
text-align: center;
padding: 1em;
border: 1px solid #eee;
background-color: #ffffff;
text-transform: uppercase;
font-size: 1em;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.45s ease-in-out, border 0.45s ease-in-out;
:hover {
background-color: #eee;
border: 1px solid black;
}
`
class FoodList extends Component {
state = {
data: {
e5d9d9f5: {
label: 'ice cream',
isDelicious: true,
isHealthy: false,
},
a9ba692b: {
label: 'pizza',
isDelicious: true,
isHealthy: false,
},
ze128a47: {
label: 'spinach',
isDelicious: false,
isHealthy: true,
},
},
}
renderListItems = () => {
const { data } = this.state
return Object.keys(data).map((key) => {
return <FoodListItem
key={key}
{...data[key]}
id={key}
handleDecliousChange={this.handleDecliousChange}
handleHealthyChange={this.handleHealthyChange}
/>
})
}
handleDecliousChange = (id) => {
this.setState(state => ({
data: {
...state.data,
[id]: {
...state.data[id],
isDelicious: !state.data[id].isDelicious
}
}
}))
}
handleHealthyChange = (id) => {
this.setState(state => ({
data: {
...state.data,
[id]: {
...state.data[id],
isHealthy: !state.data[id].isHealthy
}
}
}))
}
handleShowAppState = () => {
console.log(this.state.data)
}
render() {
return (
<Wrapper>
{this.renderListItems()}
<Button type="button" onClick={this.handleShowAppState}>Show App State</Button>
</Wrapper>
)
}
}
export default FoodList;
Here's the component which renders a single list item
import React from 'react'
import styled from 'styled-components'
const Title = styled.p`
text-transform: uppercase;
font-weight: bold;
`
const Item = styled.div`
padding: 1em 1em 1em 0em;
padding-left: ${props => props.isDelicious ? '30px': '0px'}
margin-bottom: 2em;
background-color: ${props => props.isHealthy ? 'green' : 'gray'};
transition: background-color 0.45s ease-in-out, padding-left 0.45s ease-in-out;
color: #ffffff;
`
class FoodListItem extends React.PureComponent {
deliciousFn = () => {
this.props.handleDecliousChange(this.props.id)
}
healthyFn = (id) => {
this.props.handleHealthyChange(this.props.id)
}
render() {
console.log('render called', this.props.label);
const {
id,
label, isDelicious, isHealthy,
handleDecliousChange, handleHealthyChange
} = this.props
return (
<Item isHealthy={isHealthy} isDelicious={isDelicious}>
<Title>{label}</Title>
<div>
<input type="checkbox" checked={isDelicious} onChange={this.deliciousFn} />
<label><code>isDelicious</code></label>
</div>
<div>
<input type="checkbox" checked={isHealthy} onChange={this.healthyFn} />
<label><code>isHealthy</code></label>
</div>
</Item>
)
}
}
export default FoodListItem
Whenever I click on a single list item, it re-renders all of them. Is there a way to avoid this? Ideally, only the row which was clicked on should re-render.
You should implement shouldComponentUpdate to handle component’s output in FoodListItem:
Use shouldComponentUpdate() to let React know if a component’s output
is not affected by the current change in state or props. The default
behavior is to re-render on every state change, and in the vast
majority of cases you should rely on the default behavior.
class FoodListItem extends React.Component {
//...
shouldComponentUpdate(nextProps) {
return (
this.props.isDelicious !== nextProps.isDelicious ||
this.props.isHealthy !== nextProps.isHealthy
)
}
//...
}
Reference: https://reactjs.org/docs/react-component.html#shouldcomponentupdate
Or consider using the PureComponent: https://reactjs.org/docs/react-api.html#reactpurecomponent

How to open a particular accordion based click event in reactjs and autoclose remaining accordion?

I want to open a particular Section on clicking on that. How to do that by using click event? And also auto close the remaining accordion if I click on another accordion. Here is my code.
Accordion Component
import React, { Component } from 'react';
import Section from './section';
class Accordion extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = {
open: false,
headingClassName: 'accordion-heading',
className: 'accordion-content accordion-close',
Label: 'label-close',
icon: "+",
selectedItem: null,
};
}
handleClick = () => {
const open = this.state.open;
if (open) {
this.setState({
open: false,
className: "accordion-content accordion-close",
headingClassName: "accordion-heading",
Label: 'label-close',
icon: "+",
})
} else {
this.setState({
open: true,
className: "accordion-content accordion-open",
headingClassName: "accordion-heading clicked",
Label: 'label-open',
icon: "-",
})
}
}
render() {
return (
<div className="accordion-container">
<h1>Accordian Component</h1>
How to pass id as parameter in each section in onClick event to open
particular accordion and to autoclose remaining.
<Section>
<div className={this.state.headingClassName} onClick={this.handleClick} id="1">
<h3>One</h3> <label className={this.state.Label}>{this.state.icon}</label>
</div>
<div className={this.state.className}>
<p>This is paragraph</p>
</div>
</Section>
<Section>
<div className={this.state.headingClassName} onClick={this.handleClick} id="2">
<h3>Two</h3> <label className={this.state.Label}>{this.state.icon}</label>
</div>
<div className={this.state.className}>
<p>This is paragraph</p>
</div>
</Section>
<Section>
<div className={this.state.headingClassName} onClick={this.handleClick} id="3">
<h3>Three</h3> <label className={this.state.Label}>{this.state.icon}</label>
</div>
<div className={this.state.className}>
<p>This is paragraph</p>
</div>
</Section>
</div>
);
}
}
export default Accordion;
Section Component
import React, { Component } from 'react';
class Section extends Component {
render() {
return (
<div className="parent-accordion">
{this.props.children}
</div>
);
}
}
export default Section;
CSS
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
.accordion-container {
margin: auto;
width: 700px;
}
.accordion-container h1 {
color: #0000007a;
text-align: center;
font-family: sans-serif;
}
.parent-accordion {
width: 100%;
border: 1.5px solid #00000017;
}
.accordion-heading {
padding: 5px 5px;
background-color: #e2e2e254;
cursor: pointer;
text-transform: capitalize;
/* font-size: 17px; */
/* font-weight: 600; */
color: #2b2b41;
/* font-family: sans-serif; */
transition: background-color 1s;
}
.accordion-heading:hover {
background-color: #000000c7;
color: white;
First of all i've encompased a minimal (no css) example of how an accordion would behave on codesandbox, here.
This can be done multiple ways. In the example above the body of the tab is hidden with display:none if the tab is not active.Basically you iterate over your data in the render function and that's where you set your classes based on whatever flags you want (in your case isActive). You could render a Section for each tab and pass props to it.
The click handler updates your state with the id of the active tab.

React-modal hides behind elements

I am trying to make use of react-modal for the first time. When I click on the sign-in button, the react-modal component is invoke but seems to be hiding behind the cover page which is a video landing page.
The React devtool displays the appropriate states before the sign-in button is clicked
before the sign-in button is clicked
When the sign-in button is now clicked, the react devtool now displays that the ModalPortal component is rendered showing the appropriate states
when the sign-in button is clicked
SignInModal.scss
.ReactModalPortal>div {
opacity: 0;
}
.ReactModalPortal .ReactModal__Overlay {
align-items: center;
display: flex;
justify-content: center;
transition: opacity 200ms ease-in-out;
}
.ReactModalPortal .ReactModal__Overlay--after-open {
opacity: 1;
}
.ReactModalPortal .ReactModal__Overlay--before-close {
opacity: 0;
}
.modal {
position: relative;
background: #464b5e;
color: white;
max-width: 90rem;
outline: none;
padding: 3.2rem;
text-align: center;
}
.modal__title {
margin: 0 0 1.6rem 0;
}
.modal__body {
font-size: 2rem;
font-weight: 300;
margin: 0 0 3.2rem 0;
word-break: break-all;
}
CoverPage.js Component
import Header from './Header';
import HeaderVideo from './HeaderVideo';
import SignInModal from './SignInModal';
import React, { Component } from 'react';
class CoverPage extends Component {
state = {
modalIsOpen: false
};
onOpenModal = () => {
this.setState(() => ({
modalIsOpen: true
}));
};
onCloseModal = () => {
this.setState(() => ({
modalIsOpen: false
}));
};
render() {
return (
<div>
<Header />
<HeaderVideo onOpenModal={this.onOpenModal} />
<SignInModal
modalIsOpen={this.state.modalIsOpen}
onOpenModal={this.onOpenModal}
onCloseModal={this.onCloseModal}
/>
</div>
);
}
}
export default CoverPage;
HeaderVideo.js Component
import React from 'react';
import Signup from './Signup';
import CoverInfo from './CoverInfo';
const HeaderVideo = props => {
return (
<div className="video-container">
<video preload="true" autoPlay loop volume="0" postoer="/images/1.jpg">
<source src="images/vine.mp4" type="video/mp4" />
<source src="images/vine1.webm" type="video/webm" />
</video>
<div className="video-content">
<div className="container content">
<div className="row">
<div className="col-md-9">
<CoverInfo onOpenModal={props.onOpenModal} />
</div>
<div className="col-md-3">
<Signup />
</div>
</div>
</div>
</div>
</div>
);
};
export default HeaderVideo;
CoverInfo.js Component
import React from 'react';
const CoverInfo = props => {
return (
<div className="info">
<div>
<h1>Welcome to EventCity!</h1>
</div>
<div>
<p>
At EventCity! we pride ourselves on the unrivalled personal {`event`} services,we provide
to our clientele. We guide you from the stressful decision making {`process`},ensuring you
are comfortable,whether it is a wedding, corporate {`function `}or even a kiddies party,we
create a buzz around you, taking you to the next level.
</p>
</div>
<div>
<h3>Innovation, {`Performance`} and Delivery</h3>
</div>
<button type="button" className="btn btn-success btn-lg" onClick={props.onOpenModal}>
Sign In here
</button>
</div>
);
};
export default CoverInfo;
video-cover.scss
video {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
min-width: 100%;
min-height: 100%;
width: auto;
height: auto;
z-index: 1;
}
.video-content {
z-index: 2;
position: absolute;
background: rgba(0, 0, 0, 0.6);
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.content {
padding-top: 120px;
}
You need to set the z-index property on the Modal's overlay, which normally has a z-index of 0. The CSS class is .ReactModal__Overlay
Here is the pure-React way of doing it:
const customStyles = {
content : {
...
},
overlay: {zIndex: 1000}
};
<Modal style={customStyles}>
...
</Modal>
.modal {
position: fixed;
z-index:9999;
top :0;
left:0;
right:0;
bottom:0;
background: #464b5e;
color: white;
outline: none;
padding: 3.2rem;
text-align: center;
}
Example of react-modal inline styles Set the styles in the react-modal inline styles. The z-index to 100 but make just like below
style={{
overlay: {
zIndex: 100,
backgroundColor: 'rgba(70, 70, 70, 0.5)',
},

React sharable panel url

Consider my following snippet. Right now on button click it opens a div-three that loads AnotherComponent.The url is simply 'http://localhost:3000/de' i.e. Indexroot
What I want to achieve is: If I hit 'http://localhost:3000/de/?open' then I want the panel i.e. div-three already open.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
showThird: false
}
this.showDivThree = this.showDivThree.bind(this)
/*if(props.location.search=="?open"){
this.showDivThree()
}*/
}
showDivThree() {
this.setState(prevState => ({ showSecond: false, showThird: !prevState.showThird}))
console.log(this.state)
}
render() {
return (
<div className={'wrapper' + ( this.state.showThird ? ' show' : '')}>
<div className="one">one
{/* Show third */}
<div>
<button onClick={this.showDivThree}>{this.state.showThird ? 'hideThird' : 'showThird'}</button>
</div>
</div>
<div className="three">three
<div>
<button onClick={this.showDivThree}>{this.state.showThird ? 'hideThird' : 'showThird'}</button>
<AnotherComponent />
</div>
</div>
</div>
)
}
}
class AnotherComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<div>
<h4>Another component</h4>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
.wrapper {
overflow: hidden;
white-space: nowrap;
}
.one, .two, .three {
background: #333;
border: 2px solid #787567;
box-sizing: border-box;
color: #fff;
display: inline-block;
font-family: arial;
overflow: hidden;
padding: 20px;
text-align: center;
transition: border 0.2s, padding 0.2s, width 0.2s;
min-height: 50vh;
}
.one {
width: 100%;
}
.two {
border-width: 2px 0;
padding: 20px 0;
width: 0;
}
.three {
border-width: 2px 0;
padding: 20px 0;
width: 0;
}
.show .one, .show .two, .show .three {
border-width: 2px;
padding: 20px;
width: 50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://unpkg.com/react-router/umd/react-router.min.js"></script>
<div id="root"></div>
I have commented a code where I read search string from props.location, if it is present then I simply call the function that opens the div-three. But as I have mixed conditions to open divs it somehow is not working.
How can I fix this?
You can't call setState (showDivThree method calls setState) in contructor since when constructor is called component hasn't been mounted yet. Please check this SO answer for more details.
You should move if statement checking URL search string from constructor to componentDidMount method which is called immediately after a component is mounted and in which you can safely use setState:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
showThird: false
};
this.showDivThree = this.showDivThree.bind(this)
}
componentDidMount() {
if (props.location.search == "?open") {
this.showDivThree();
}
}
...
}
Besides, I think that your URL should be without slash before search query. So it should be http://localhost:3000/de?open instead of http://localhost:3000/de/?open.

simple css animation not working on dynamic reactjs element

Check the snippet at codepen http://codepen.io/anon/pen/EZJjNO
Click on Add button, it will add another item but its appearing immediately without any fade effect.
JS:
class App extends React.Component {
constructor(props) {
super(props);
this.addItem = this.addItem.bind(this);
this.state = {
items: [1,2,3]
}
}
addItem() {
var items = this.state.items;
items.push(4);
this.setState({
items: items
})
}
render() {
return (
<div className="App">
{
this.state.items.map(function(i) {
return <div className="item fade">Testing</div>
})
}
<button onClick={this.addItem}>Add</button>
</div>
);
}
}
React.render(<App />, document.body);
CSS:
.App {
background-color: rgba(0,0,0, 0.5);
text-align: center;
height: 100vh;
}
div.item {
border: 1px solid #ccc;
padding: 10px;
background: #123456;
color: #fff;
opacity: 0;
transition: all 0.4s ease-out;
}
.fade {
opacity: 1 !important;
}
Since the fade class is added by default, you don't get the transition effect. If you open your browser's developer tools and remove the class, you'll see it fade away nicely.
There's a few ways to get what you want, but I'd just use a keyframe CSS animation like so:
.fade {
animation: 0.4s ease-out fadeIn 1;
}
#keyframes fadeIn {
0% {
opacity: 0;
visibility: hidden;
}
100% {
opacity: 1;
visibility: visible;
}
}
Here's a fork of your code pen showing how it works :)

Resources