React conditionally opening different divs - reactjs

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>

Related

Input checkbox didn't work what I expected

I tried to make an input checkbox when I click the input checkbox, it should be displayed a check image like this.
However, it didn't show the checkbox and I am not sure how to check that the input box was checked or not. Could you help me with what part do I missed and where is something wrong?
I really appreciate your help!
This is CSS inputl and label part
.colors {
display: flex;
flex-direction: column;
span {
margin-bottom: 20px;
}
.colorLists {
margin-left: 10px;
display: flex;
flex-wrap: wrap;
.colorLayout {
display: flex;
flex-direction: column;
position: relative;
width: 33%;
height: 80px;
flex-shrink: 0;
align-items: center;
justify-content: center;
.checkboxLabel {
background-color: beige;
border: 1px solid #ccc;
border-radius: 50%;
cursor: pointer;
height: 28px;
left: 0;
position: absolute;
top: 40;
width: 28px;
&:after {
border: 2px solid #fff;
border-top: none;
border-right: none;
content: '';
height: 6px;
left: 7px;
opacity: 0;
position: absolute;
top: 8px;
transform: rotate(-45deg);
width: 12px;
// opacity: 0.2;
}
}
input[type='checkbox'] {
visibility: hidden;
}
input[type='checkbox']:checked {
& + label {
background-color: beige;
border-color: beige;
&:after {
opacity: 1;
}
}
}
.productColor {
margin-top: 70px;
font-size: 13px;
margin-right: 21px;
}
}
}
}
.sizes {
.HorizontalLine {
margin-top: 25px;
}
.span {
}
.sizeLists {
margin-top: 20px;
margin-bottom: 20px;
button {
margin: 5px;
width: 44px;
height: 32px;
background-color: white;
border: 1px solid silver;
border-radius: 15%;
}
}
}
This is js part
<div className="colors">
<span>색상</span>
<ul className="colorLists">
{COLOR_LISTS.map((color, idx) => {
return (
<li className="colorLayout" key={idx}>
<input type="checkbox" />
<label
className="checkboxLabel"
for="checkbox"
style={{ backgroundColor: color.colorProps }}
/>
<span className="productColor">{color.color_name}</span>
</li>
);
})}
</ul>
</div>
In react you have to set the htmlFor property for the label instead of for.
The value should be the same as the id from the input.
Then you can add a value property for the input which is used for adding/removing the item in the list of selected items.
For this purpose a handleChange function can be defined.
const [selectedItems, setSelectedItems] = useState([]);
function handleChange(e) {
let newSelected = [];
if (selectedItems.includes(e.target.value)) {
newSelected = selectedItems.filter((item) => item !== e.target.value);
} else {
newSelected = [...selectedItems, e.target.value];
}
setSelectedItems(newSelected);
}
return (
<div className="colors">
<span>색상</span>
<ul className="colorLists">
{COLOR_LISTS.map((color, idx) => {
return (
<li className="colorLayout" key={idx}>
<input
onChange={handleChange}
type="checkbox"
id={idx}
value={color.color_name}
checked={selectedItems.includes(color.color_name)}
/>
<label
className="checkboxLabel"
htmlFor={idx}
style={{ backgroundColor: color.colorProps }}
/>
<span className="productColor">{color.color_name}</span>
</li>
);
})}
</ul>
</div>
);
EDIT: Since you are using a class component it can be rewrittenlike this:
export default class CheckboxListComponent extends Component {
constructor(props) {
super(props);
this.state = { selectedItems: [] };
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
let newSelected = [];
if (this.state.selectedItems.includes(e.target.value)) {
newSelected = this.state.selectedItems.filter(
(item) => item !== e.target.value
);
} else {
newSelected = [...this.state.selectedItems, e.target.value];
}
this.setState({ selectedItems: newSelected });
}
render() {
return (
<div className="colors">
<span>색상</span>
<ul className="colorLists">
{COLOR_LISTS.map((color, idx) => {
return (
<li className="colorLayout" key={idx}>
<input
onChange={this.handleChange}
type="checkbox"
id={idx}
value={color.color_name}
checked={this.state.selectedItems.includes(color.color_name)}
/>
<label
className="checkboxLabel"
htmlFor={idx}
style={{ backgroundColor: color.colorProps }}
/>
<span className="productColor">{color.color_name}</span>
</li>
);
})}
</ul>
</div>
);
}
}
You must tell react that your input is checked so that your CSS will apply it. selected ids must be kept in a place for future existence check. in the following code, I named this array selecetedIdx.
You also need to add idx on selection(via onChange event handler) or wrap them all in form and add them via extra dom attribute.
class Main extends Component {
// initialize selectedIdx with [] in your state (esp constructor)
// e.g. this.state = {/* rest of state, */ selectedIdx: []}
render() {
return (
{COLOR_LISTS.map((color, idx) => {
return (
// ...
<input
type="checkbox"
checked={selectedIdx.includes(idx)}
onChange={() => this.setState(state => ({
selectedIdx: [...state.selectedIdx, idx]
}))}
/>
// ...
)}
)
}
Your checkbox element needs name and value properties and would normally be a child of the <form> element.

React nested loop bug

I am trying to build on the beginner react tutorial.
The below code compiles successfully in terminal. Note, only the lines from "Square" downwards are directly relevant, I think.
index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
const size = 30
class DropDown extends React.Component{
algorithm_states = {
alg:0,
}
algClick(i){
this.algorithm_states.alg = i;
}
startResetClick(i){
switch(i){
default:
case 0:
//enable disable buttons on grid
//run relevent processes bases on algorithm state machine
break;
case 1:
// clear grid and matrix
// enable buttons on grid
break;
}
}
render(){
return(
<header>
<button className = "main">
Main
</button>
<div className="dropdown">
<span>Choose Rule</span>
<div className="dropdown-content">
{/* algorithms mapped to their indicies in list */}
<button
onClick={() => this.algClick(0)}
>Game Of Life</button>
<button
onClick={() => this.algClick(1)}
>Langtons Ant</button>
</div>
</div>
{/* start button mapped to 0, reset button mapped to 1 */}
<button
className = "start"
onClick={() => this.startResetClick(0)}
>START</button>
<button
className = "stop"
onClick={() => this.startResetClick(1)}
>RESET</button>
</header>
)
}
}
class Square extends React.Component {
keys = {
x:null,
y:null,
}
render() {
return (
<button className="square" key = {this.keys.x + this.keys.y}>
</button>
);
}
}
class Board extends React.Component{
renderSquare(x, y) {
return (
<Square
keys = {[x,y]}/>
);
}
render(){
const rows = [], cols = [];
for(var i = 0; i < size; i++){
rows[i] = i;
cols[i] = i;
}
return(
<div>
{[...rows].map((x) => {
return (
<div className="board-row" key={x}>
{[...cols].map((y) => this.renderSquare(x,y))}
</div>
)
})
}
</div>
)
}
}
class Game extends React.Component {
render() {
return (
<div className="game">
<header className = "header">
<DropDown/>
</header>
<body>
<div className="game-board">
<Board />
</div>
</body>
</div>
);
}
}
// ========================================
ReactDOM.render(
<Game />,
document.getElementById('root')
);
index.css
body {
font: 14px "Century Gothic", Futura, sans-serif;
margin: 20px;
}
ol, ul {
padding-left: 30px;
}
.header{
background: "black";
}
.main {
position: absolute;
left: 5%
}
.game-board{
position: absolute;
top: 20%;
left:30%;
}
.board-row:after {
clear: both;
content: "";
display: table;
}
.status {
margin-bottom: 10px;
}
.square {
background: #fff;
border: 1px solid #999;
float: left;
font-size: 10px;
font-weight: bold;
line-height: 15px;
height: 15px;
margin-right: -1px;
margin-top: -1px;
padding: 0;
text-align: center;
width: 15px;
}
.square:focus {
outline: none;
}
.kbd-navigation .square:focus {
background: #ddd;
}
.game {
display: flex;
flex-direction: row;
}
.game-info {
margin-left: 20px;
}
.dropdown {
position: absolute;
top: 20%;
left: 5%;
display: inline-block;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
padding: 12px 16px;
z-index: 1;
}
.dropdown:hover .dropdown-content {
display: block;
}
.start{
position: absolute;
right: 15%;
}
.stop{
position: absolute;
right: 5%;
}
But in browser, I get the error
Warning: Each child in a list should have a unique "key" prop.
Check the render method of `Board`. See https://reactjs.org/link/warning-keys for more information.
Square#http://localhost:3000/static/js/main.chunk.js:249:5
Board#http://localhost:3000/static/js/main.chunk.js:268:1
div
body
div
Game#http://localhost:3000/static/js/main.chunk.js:308:1
And I'm not sure what it's about, since I'm pretty sure all the keys I have provided are unique.
Anyone got any ideas???
Cheers
K
You need to render each Square component with a key at the map level:
render(){
const rows = [], cols = [];
for(var i = 0; i < size; i++){
rows[i] = i;
cols[i] = i;
}
return(
<div>
{[...rows].map((x) => {
return (
<div className="board-row">
{[...cols].map((y) => (
<Square keys={[x,y]} key={`x-y`} />
))}
</div>
)
})
}
</div>
)
}
}
See the reference on the docs

Why is git pages rendering my page different then in local?

I'm rather new to whole react thing, going through courses on FCC. My problem come from CSS/SCSS itself. I tried ordinary CSS and SCSS. My page is done in React. The page is also hosted on codepen. All three versions are the same, codepen, git and local and yet CSS is somewhat different between them. My previous projects who are also hosted on these platforms and in local have also the same CSS but they look identical. Difference between local and codepen's version isn't that drastic, but between local>codepen>github is more than noticeable as you descend. Do GitHub ignores/renders? or what, React differently? This question should also apply to codepen.
My codepen
My git page
My repoToProject
Image of localhost:
html from codepen:
<div id="root"></div>
scss from codepen:
$position: absolute;
$percentage: 100%;
$color: whitesmoke;
$car: auto;
#import url("//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-glyphicons.css");
.btn1 {
position: $position;
bottom: -30px;
left: 51.3%;
z-index: 999;
background-color: $color;
border: 1px solid gray;
color: aqua;
}
#root {
width: $percentage;
}
body,
html {
height: $percentage;
}
body {
background-color: $color;
background-image: url("../images/react1.png");
background-repeat: no-repeat;
background-size: $car;
background-position: center bottom;
overflow: hidden;
}
.grid-container {
display: grid;
grid-template-columns: 50% 50%;
background-color: $color;
padding: 10px;
grid-gap: 15px;
width: $percentage;
grid-template-rows: 30px 25px 98%;
}
.grid-item {
text-align: center;
}
#inner2 {
padding-left: 20px;
padding-right: 25px;
border-bottom: 15px solid #d6e9c6;
padding-bottom: 55px;
background-color: #fcf8e3;
width: $percentage;
margin-left: $car;
margin-right: $car;
position: $position;
top: 0px;
left: 0px;
height: $percentage;
min-height: 20%;
max-height: $percentage;
}
#editor {
width: $percentage;
background-color: white;
resize: none;
color: #495057;
border: 1px solid #ced4da;
border-radius: 0.25rem;
overflow-y: $car;
max-height: $percentage;
min-height: 40px;
margin-bottom: 40px;
}
#preview {
width: 98.9%;
background-color: white;
border-radius: 0.25rem;
border: 1px solid #ced4da;
overflow-y: $car;
max-height: $percentage;
min-height: 40px;
margin-bottom: 40px;
}
#item1,
#item2 {
font-family: "Russo One";
font-style: oblique;
font-weight: bold;
font-size: 2em;
margin-bottom: 10px;
padding-bottom: 0px;
width: $percentage;
background-color: #fcf8e3;
min-height: 50px;
border-bottom: none;
padding-top: 10px;
}
.insignia {
letter-spacing: 5px;
-webkit-transition: letter-spacing 1s;
transition: letter-spacing 1s;
}
.insignia:hover {
letter-spacing: 13px;
cursor: pointer;
}
.ui-resizable-s {
cursor: row-resize;
}
textarea:focus,
input:focus {
outline: none;
}
#arrow {
background-color: #dff0d8;
width: $percentage;
height: 15px;
position: $position;
bottom: -12px;
padding-left: 0px;
padding-right: 0px;
font-size: 1.5em;
border-bottom: 1px solid #d6e9c6;
text-align: center;
}
.glyphicon {
top: -4px;
left: 4px;
color: gray;
-ms-transform: scale(1, 0.6); /* IE 9 */
-webkit-transform: scale(1, 0.6); /* Safari */
transform: scale(1, 0.6);
}
#media screen and (max-height: 600px) {
#inner2 {
height: 90vh !important;
}
}
#eraser {
text-align: center;
grid-column: 1 / 3;
z-index: 2;
line-height: 10px;
margin-left: $car;
margin-right: $car;
}
/*Additional styling*/
td,
th {
border: 2px solid #224b4b;
padding-left: 5px;
padding-right: 5px;
}
.label {
position: $position;
top: -10px;
left: 0px;
min-width: $percentage;
z-index: 999;
}
.preview-editor {
position: fixed;
top: 55px;
left: 0px;
min-width: $percentage;
height: $percentage;
z-index: 999;
}
h1 {
border-bottom: 2px solid #224b4b;
}
h2 {
border-bottom: 1px solid #224b4b;
}
code {
background-color: #d6e9c6;
color: #e83e8c !important;
}
blockquote {
border-left: 2px solid black;
padding-left: 5px;
margin-left: 25px;
}
#media only screen and (max-width: 768px) {
img {
width: 100%;
}
#ggED {
text-align: left;
}
#ggPrev {
text-align: right;
}
.insignia,
.insignia:hover {
letter-spacing: 0px;
font-size: 1em;
}
}
js from codepen:
var renderer = new marked.Renderer();
renderer.link = function(href, title, text) {
return (
'<a target="_blank" href="' +
href +
'" title="' +
title +
'">' +
text +
"</a>"
);
};
marked.setOptions({
breaks: true,
renderer: renderer,
sanitize: true
});
class DisplayMessages extends React.Component {
constructor(props) {
super(props);
this.state = {
markdown: defaultMarkdown,
erase: false,
goFull: false,
headViewKlasa: "grid-item",
headEdKlasa: "grid-item",
editorKlasa: "",
previewKlasa: "",
stilPreview: {},
stilEditor: {},
attr: "Click on me for fullscreen",
inner2H: "",
h2Inner: false
};
this.handleChange = this.handleChange.bind(this);
this.eraseFields = this.eraseFields.bind(this);
this.inner2Height = this.inner2Height.bind(this);
}
eraseFields() {
this.setState({
erase: true
});
if (this.state.erase === false) {
this.setState({
markdown: ""
});
}
if (this.state.erase === true) {
this.setState({
markdown: defaultMarkdown,
erase: !this.state.erase
});
}
}
componentDidMount() {
this.node = ReactDOM.findDOMNode(this);
$(this.node).resizable({
handles: "s",
minHeight: 170
});
document
.querySelector(".ui-resizable-handle.ui-resizable-s")
.setAttribute(
"title",
"Double click on me or pull me down to full height"
);
}
inner2Height() {
if (this.state.h2Inner === false) {
this.setState({
inner2H: "100%",
h2Inner: true
});
}
if (this.state.h2Inner === true) {
this.setState({
inner2H: "",
h2Inner: false
});
}
}
fullScreen(clicked_id) {
if (clicked_id === "ggEd" && this.state.goFull === false) {
this.setState({
headEdKlasa: this.state.headEdKlasa + " label",
attr: "Click again to go back!",
editorKlasa: "preview-editor",
stilPreview: { display: "none" },
stilEditor: { paddingTop: "0px" },
goFull: true
});
}
if (clicked_id === "ggEd" && this.state.goFull === true) {
this.setState({
headEdKlasa: this.state.headEdKlasa.substr(0, 9),
attr: "Click on me for fullscreen",
editorKlasa: "",
stilPreview: { display: "block" },
stilEditor: { paddingTop: "10px" },
goFull: !this.state.goFull
});
}
if (clicked_id === "ggPrev" && this.state.goFull === false) {
this.setState({
headViewKlasa: this.state.headViewKlasa + " label",
attr: "Click again to go back!",
previewKlasa: "preview-editor",
stilEditor: { display: "none" },
stilPreview: { paddingTop: "0px" },
goFull: true
});
}
if (clicked_id === "ggPrev" && this.state.goFull === true) {
this.setState({
headViewKlasa: this.state.headViewKlasa.substr(0, 9),
attr: "Click on me for fullscreen",
previewKlasa: "",
stilEditor: { display: "block" },
stilPreview: { paddingTop: "10px" },
goFull: !this.state.goFull
});
}
}
handleChange(event) {
this.setState({
markdown: event.target.value
});
}
render() {
const btnText = this.state.erase ? "Populate" : "Erase";
const handleClick = e => this.fullScreen(e.target.id);
return (
<div
id="inner2"
className="grid-container animated zoomIn"
style={{ height: this.state.inner2H }}
onDoubleClick={this.inner2Height}
>
<EditorHead
id={"item1"}
style={this.state.stilEditor}
className={this.state.headEdKlasa}
onClick={handleClick}
title={this.state.attr}
/>
<PreviewHead
id={"item2"}
style={this.state.stilPreview}
className={this.state.headViewKlasa}
onClick={handleClick}
title={this.state.attr}
/>
<BtnEraser
id={"eraser"}
onClick={this.eraseFields}
type={"button"}
className={"btn btn-danger btn-lg"}
title={"Erase & populate both fields"}
value={btnText}
/>
<Editor
id={"editor"}
onChange={this.handleChange}
className={this.state.editorKlasa}
value={this.state.markdown}
placeholder={"Enter ... some kind a text!? ..."}
title={
"This is rather obvious isn't it? It's editor window Sherlock :D"
}
/>
<Preview
id={"preview"}
className={this.state.previewKlasa}
dangerouslySetInnerHTML={{
__html: marked(this.state.markdown, { renderer: renderer })
}}
title={"It's a preview window, Sherlock ;)"}
/>
<Arrow id={"arrow"} />
</div>
);
}
}
/*class Inner2 extends React.Component{
render(){
return (
<div id={this.props.id} className={this.props.className} style={this.props.style} onDoubleClick={this.props.onDoubleClick}>Editor:</div>
);
}
}*/
class EditorHead extends React.Component {
render() {
return (
<h1
id={this.props.id}
style={this.props.style}
className={this.props.className}
onClick={this.props.onClick}
>
<span className="insignia" title={this.props.title} id="ggEd">
Editor:
</span>
</h1>
);
}
}
class PreviewHead extends React.Component {
render() {
return (
<h1
id={this.props.id}
style={this.props.style}
className={this.props.className}
onClick={this.props.onClick}
>
<span className="insignia" title={this.props.title} id="ggPrev">
Previewer:
</span>
</h1>
);
}
}
class BtnEraser extends React.Component {
render() {
return (
<button
id={this.props.id}
onClick={this.props.onClick}
type={this.props.type}
className={this.props.className}
title={this.props.title}
>
{this.props.value}
</button>
);
}
}
class Editor extends React.Component {
render() {
return (
<textarea
id={this.props.id}
onChange={this.props.onChange}
className={this.props.className}
value={this.props.value}
placeholder={this.props.placeholder}
title={this.props.title}
/>
);
}
}
class Preview extends React.Component {
render() {
return (
<div
id={this.props.id}
className={this.props.className}
dangerouslySetInnerHTML={this.props.dangerouslySetInnerHTML}
title={this.props.title}
/>
);
}
}
class Arrow extends React.Component {
render() {
return (
<div id={this.props.id}>
<Glyph className={"glyphicon glyphicon-align-justify"} />
</div>
);
}
}
class Glyph extends React.Component {
render() {
return <span className={this.props.className} />;
}
}
ReactDOM.render(<DisplayMessages />, document.getElementById("root"));

React add css class dynamically

I have a set of tabs and I want to apply different class to the selected tab:
My component:
constructor(props) {
super(props);
this.state = {
activeTab: false,
};
}
setActiveTab = ()=> {
this.state.activeTab=true
}
render() {
return (
<HtmlPage>
<div className="tab">
<InternalLink to={`/settings/user-profile`} >
<div className="tablinks">Nutzerprofil</div>
</InternalLink>
<InternalLink to={`/settings/company-profile`} >
<div className={this.state.activeTab ? 'active':'tablinks'} onClick={this.setActiveTab}>Firmenprofil</div>
</InternalLink>
<InternalLink to={`/settings/user-profile`} >
<div className="tablinks">Nutzerverwaltung</div>
</InternalLink>
</div>
<div className="content">
{this.props.children}
</div>
</HtmlPage>
);
}
And my css:
/* Style the tab */
div.tab {
padding-top: 1%;
overflow: hidden;
border: 1px solid #ccc;
}
/* Style the buttons inside the tab */
div.tab .tablinks {
background-color: inherit;
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
font-size: 20px;
}
/* Change background color of buttons on hover */
div.tab .tablinks:hover {
background-color: #ddd;
}
/* Create an active/current tablink class */
div.tab .active {
float: left;
border: none;
outline: none;
cursor: pointer;
padding: 14px 16px;
transition: 0.3s;
font-size: 20px;
background-color: #ccc;
}
However, this just sets the class to active for the first clicked tab and not each time I select another tab. How can I fix it?
Set a name for the active tab on click, and then compare while setting the class like
constructor(props) {
super(props);
this.state = {
activeTab: '',
};
}
setActiveTab = (val, e)=> {
this.setState({activeTab: val})
}
<div className="tab">
<InternalLink to={`/settings/user-profile`} >
<div className={this.state.activeTab == 'user-profile' ? 'active':'tablinks'} onClick={this.setActiveTab.bind(this, 'user-profile')}>Nutzerprofil</div>
</InternalLink>
<InternalLink to={`/settings/company-profile`} >
<div className={this.state.activeTab == 'company-profile ? 'active':'tablinks'} onClick={this.setActiveTab.bind(this, 'company-profile')}>Firmenprofil</div>
</InternalLink>
<InternalLink to={`/settings/user-profile`} >
<div className={this.state.activeTab == 'user-profile1 ? 'active':'tablinks'} onClick={this.setActiveTab.bind(this, 'user-profile2')}>Nutzerverwaltung</div>
</InternalLink>
</div>

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.

Resources