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.
Related
I have some state that changes after button click. The state changes the size of a sidebar.
Here is my CSS made with styled-components and conditional rendering:
const SidebarStyled = styled.div`
width: ${this.state.sidebarOpen ? '200px' : '70px'};
position: fixed;
left: 0px;
top: 0px;
height: 100vh;
background-color: #0c1635;
display: flex;
flex-direction: column;
`;
Any idea how I can apply a transition 0.2s on the conditional rendering?
I have tried to add transition: all 0.2s ease-in-out; and it didn't work.
As I mentioned in my comment, you need to pass in a prop and interpolate it out to change your CSS. Otherwise your component will re-render, and the CSS transition won't be applied.
const { React, ReactDOM, styled } = window;
class WontWork extends React.Component {
constructor(props) {
super(props);
this.state = { sidebarOpen: false };
}
render() {
const Sidebar = styled.div`
width: ${this.state.sidebarOpen ? "200px" : "70px"};
height: 20px;
background: red;
transition: width 1s;
`;
return (
<main>
<p>This won't work:</p>
<Sidebar />
<button
onClick={() => this.setState({ sidebarOpen: !this.state.sidebarOpen })}
>
Expand
</button>
</main>
);
}
}
const WorkingSidebar = styled.div`
width: ${(props) => (props.open ? "200px" : "70px")};
height: 20px;
background: green;
transition: width 1s;
`;
class WillWork extends React.Component {
constructor(props) {
super(props);
this.state = { sidebarOpen: false };
}
render() {
return (
<main>
<p>You need to pass in a <b>prop</b> to a predefined styled-component:</p>
<WorkingSidebar open={this.state.sidebarOpen} />
<button
onClick={() => this.setState({ sidebarOpen: !this.state.sidebarOpen })}
>
Expand
</button>
</main>
);
}
}
ReactDOM.render(
<div>
<WontWork />
<hr />
<WillWork />
</div>,
document.getElementById("app")
);
<script crossorigin src="https://unpkg.com/react#16.14.0/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16.14.0/umd/react-dom.development.js"></script>
<script crossorigin src="https://unpkg.com/react-is#16.13.1/umd/react-is.production.min.js"></script>
<script crossorigin src="https://unpkg.com/styled-components#5.3.3/dist/styled-components.min.js"></script>
<div id="app"></div>
Try this:
You can passe sidebarOpen as props:
<SidebarStyle sidebarOpen = {this.state.sidebarOpen}>
Then:
const sidebarStyle = styled.div`
width: 70px;
transition: transform .2s ease-in-out;
transform: ${props.sidebarOpen ? "scaleX(3)" : "scaleX(1)"};
.
.
.
`
I helped from here:
See here: Adding transitions to styled components
Does it work In this case?
Add a transition property like: transition:all 200ms ease-in;
I would like to change the class name of my list items based on information passed on keys. But obviously I am doing something wrong.
On every click I like to update the state with key then based on this state I would like to set the class name as active and active CSS should change the style of the list item
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {
activeIndex: 0
}
this.ChangeColor = this.ChangeColor.bind(this);
}
ChangeColor(key) {
this.setState({
activeIndex: key
})
console.log(this.state.activeIndex)
}
render() {
return (
<div id='header' >
CompanyLogo
<div id='buttons' >
<li key = {0} className={this.state.activeIndex==0 ? 'active' : null } onClick = {this.ChangeColor} >Home</li>
<li key = {1} className={this.state.activeIndex==1 ? 'active' : null } onClick = {this.ChangeColor} >Features</li>
<li key = {2} className={this.state.activeIndex==2 ? 'active' : null } onClick = {this.ChangeColor} >How It Works</li>
</div>
</div>
)
}
}
class App extends React.Component{
constructor(props){
super(props)
}
render() {
return(
<div>
<Header />
</div>
)
}
}
ReactDOM.render(<App />, document.querySelector("#app"))
#header {
overflow: hidden;
background-color: #f4f4f4;
padding: 20px 10px;
}
#buttons{
float:right;
}
#buttons > .active {
background-color: #008CBA; /* Green */
border-radius: 5px;
color: white;
padding: 10px 10px;
text-align: center;
display: inline-block;
font-size: 16px;
margin: 2px
}
#buttons > li {
background-color: white;
border-radius: 5px;
color: #008CBA;
padding: 10px 10px;
text-align: center;
display: inline-block;
font-size: 16px;
margin: 2px
}
#buttons > li:hover {
cursor: pointer;
}
<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>
<div id="app"></div>
The reason that your program doesn't work is that you are not passing any key when you call ChangeColor. Hence, after the first click your activeIndex will be undefined. You need to modify these three lines, as shown below, to ensure ChangeColor knows the key of the item that is clicked. Please notice that you cannot call the function directly like this this.ChangeColor(0).
<li key={0} className={this.state.activeIndex == 0 ? 'active' : null} onClick={() => this.ChangeColor(0)} >Home</li>
<li key={1} className={this.state.activeIndex == 1 ? 'active' : null} onClick={() => this.ChangeColor(1)} >Features</li>
<li key={2} className={this.state.activeIndex == 2 ? 'active' : null} onClick={() => this.ChangeColor(2)} >How It Works</li>
You need to pass the key/index into the change color function for each item
onClick = {() => this.ChangeColor(0)}
onClick = {() => this.ChangeColor(1)}
etc..
then what you have done should work
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>
);
}
i want to built an multi select checkbox dropdown in react with es6
my requirement is as below specified in image
I tried doing this click here but it is not working.
You can use one parent component that will keep values in its state and toggle list items. Then you can create component for each list item that will keep active property in state that you can toggle on click.
class ListItem extends React.Component {
constructor(props) {
super(props);
this.state = {active: false}
}
render() {
return (
<a
onClick={() => {
this.setState(prevState => {
let newState = !prevState.active;
this.props.handleClick(newState, this.props.value);
return {active: newState}
})
}}
className={!this.state.active ? '' : 'selected'}
href="#">
{this.props.value}</a>
)
}
}
class Select extends React.Component {
constructor(props) {
super(props);
this.state = {
showList: false,
value: []
}
this.handleItemClick = this.handleItemClick.bind(this)
}
componentDidMount() {
document.addEventListener('mousedown', (e) => {
if(!this.node.contains(e.target)) {
this.setState({showList: false})
}
})
}
componentWillUnmount() {
document.removeEventListener('mousedown');
}
renderValue() {
let {value} = this.state;
if(!value.length) return "Select..."
else return value.join(', ')
}
toggleList() {
this.setState(prevState => ({showList: !prevState.showList}))
}
handleItemClick(active, val) {
let {value} = this.state;
if(active) value = [...value, val]
else value = value.filter(e => e != val);
this.setState({value})
}
render() {
return (
<div
ref={node => this.node = node}
className="select">
<button onClick={this.toggleList.bind(this)}>
<span className="select_value">
{this.renderValue()}
</span>
</button>
<div
className={"select_list " + (!this.state.showList && 'hide')}>
<ListItem handleClick={this.handleItemClick} value="Lorem" />
<ListItem handleClick={this.handleItemClick} value="Ipsum" />
<ListItem handleClick={this.handleItemClick} value="Dolor" />
</div>
</div>
)
}
}
ReactDOM.render(
<Select />,
document.getElementById('container')
);
button {
background: white;
width: 100%;
padding: 10px 15px;
border: 1px solid rgba(0, 0, 0, .1);
border-radius: 5px;
cursor: pointer;
text-align: left;
}
.select_list {
width: 100%;
background: white;
border: 1px solid rgba(0, 0, 0, .1);
border-radius: 5px;
}
.select_list a {
padding: 10px 15px;
display: flex;
color: black;
text-decoration: none;
position: relative;
align-items: center;
}
.select_list a:before {
width: 15px;
height: 15px;
content: '';
border: 1px solid rgba(0, 0, 0, .1);
border-radius: 5px;
margin-right: 10px;
display: block;
}
.select_list a.selected:before {
background: #0493D1;
content: '✓';
color: white;
font-size: 11px;
text-align: center;
line-height: 15px;
}
.hide {
display: none;
}
<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>
<div id="container"></div>
Semantic-UI React Approach
After much digging, I found an old conversation between eugenetumachov and Semantic-UI developers(?). One of the users provided incredibly helpful code that answers this question using Semantic-UI's Dropdown component.
This is done by making use of Dropdown's Dropdown.Menu and Dropdown.Item. Then looping through your options via map to create checkboxes. The only downside is that the workaround does not seem to allow scrolling and will require more CSS. Additionally, based on CSS the checkbox items' background color may turn transparent if you double-click on the dropdown, and the dropdown will collapse on mouse hover. You can bypass the transparency issue by using a class or style property for your Dropdown.Menu and Dropdown.Item.
Semantic-UI developer's response to this type of question appears to be a flat "no" or a
Active items are automatically removed from the Dropdown menu. So you cannot show a "checked" state for an item in the menu.
You could create a similar component out of an Input as a trigger for
a Popup containing a Menu or List of Checkboxes.
Are dropdowns with checkboxes possible? #2417
eugenetumachov's workaround
I am trying to conditionally open divs two and three, take a look at following snippet. showThird works correct however, showSecond has no effect? Basically on showSecond div-one shrinks to 50% width and div-two appears in rest 50%. Similar with div-third.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
showSecond: false,
showThird: false
}
this.showDivTwo = this.showDivTwo.bind(this)
this.showDivThree = this.showDivThree.bind(this)
}
showDivTwo() {
this.setState(prevState => ({showThird: false, showSecond: !prevState.showSecond}))
console.log(this.state)
}
showDivThree() {
this.setState(prevState => ({ showSecond: false, showThird: !prevState.showThird}))
console.log(this.state)
}
render() {
return (
<div className={'wrapper' + (this.state.showSecond ? ' show' : '', this.state.showThird ? ' show' : '')}>
<div className="one">one
{/* Show second */}
<div>
<button onClick={this.showDivTwo}>{this.state.showSecond ? 'hideSecond' : 'showSecond'}</button>
</div>
{/* 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>
</div>
</div>
<div className="two">two
<div>
<button onClick={this.showDivTwo}>{this.state.showSecond ? 'hideSecond' : 'showSecond'}</button>
</div>
</div>
</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>
<div id="root"></div>
What am I doing wrong here?
Changes:
1- use this condition:
className={'wrapper' + (this.state.showSecond || this.state.showThird ? ' show' : '')}
2- Use one more class hide, and put the check on className, apply that class if you want to hide the div otherwise apply class two or three.
Check the working code:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
showSecond: false,
showThird: false
}
this.showDivTwo = this.showDivTwo.bind(this)
this.showDivThree = this.showDivThree.bind(this)
}
showDivTwo() {
this.setState(prevState => ({showThird: false, showSecond: !prevState.showSecond}))
console.log(this.state)
}
showDivThree() {
this.setState(prevState => ({ showSecond: false, showThird: !prevState.showThird}))
console.log(this.state)
}
render() {
return (
<div className={'wrapper' + (this.state.showSecond || this.state.showThird ? ' show' : '')}>
<div className="one">
one
<div>
<button onClick={this.showDivTwo}>{this.state.showSecond ? 'hideSecond' : 'showSecond'}</button>
</div>
<div>
<button onClick={this.showDivThree}>{this.state.showThird ? 'hideThird' : 'showThird'}</button>
</div>
</div>
<div className={this.state.showThird?"three":'hide'}>
three
<div>
<button onClick={this.showDivThree}>{this.state.showThird ? 'hideThird' : 'showThird'}</button>
</div>
</div>
<div className={this.state.showSecond ? "two" : 'hide'}>two
<div>
<button onClick={this.showDivTwo}>{this.state.showSecond ? 'hideSecond' : 'showSecond'}</button>
</div>
</div>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
.wrapper {
overflow: hidden;
white-space: nowrap;
}
.hide, .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%;
}
.hide {
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>
<div id="root"></div>