React not updating style - javascript

I'm trying to change style when a button is clicked using React. I can see value is changing when button is clicked, but style is not changing. I've been writing in many ways with no luck.
export const Paragraph = () => {
var state = 'none'
const changeState = () => {
state = state == 'none' ? 'inline-block' : 'none'
}
return (
<div>
<p style={{display: state}}</p>
</div>
)
}

Better way to set a class instead inline styles.
class Paragraph extends React.Component{
constructor(){
super();
this.state = {
isClicked: false
};
}
onClick(){
let condition = this.state.isClicked;
this.setState({isClicked: !condition})
}
render(){
return (
<div onClick={this.onClick.bind(this)}>
<p className={this.state.isClicked? "class_1" : "class_2"}></p>
</div>
);
}
}

Related

Using state in child component received from parent component

When I click on the menu in GeneralNav I successfully switch between true or false.
This menuState once again is passed successfully to Overlay via HomePage.
Though I'm not able to toggle the right classes in Overlay to hide or show the menu. Can someone explain me a correct workflow to add the classes on my EasyFlexCol component to show or hide it? Been stuck for a while now.
Thanks!
class GeneralNav extends Component {
render() {
return (
<div
className="nav-burger-box menu-action"
onClick={this.props.toggleMenu}
>
<div className="nav-burger-top" />
<div className="nav-burger-bottom" />
</div>
);
}
}
class HomePage extends Component {
state = {
showMenu: false
};
toggleMenu = e => {
e.preventDefault();
this.setState(state => ({ showMenu: !state.showMenu }));
};
render() {
return (
<React.Fragment>
<OverlayMenu menuState={this.state.showMenu}/>
<HeaderFullscreen />
</React.Fragment>
);
}
}
class OverlayMenu extends Component {
state = {
showMenu: "overlay-menu-wrapper bg-color-dark overlay-menu-wrapper display-block",
hideMenu: "overlay-menu-wrapper bg-color-dark overlay-menu-wrapper"
};
render() {
let menuState = this.props.menuState
console.log(menuState)
return (
<EasyFlexCol style={"here I want to add the right class to show or hide the overlay menu"}>
</EasyFlexCol>
);
}
}
You can do using ternary operation like this :
i.e if menuState is true show showMenu else vice versa
<EasyFlexCol className={menuState ? showHide.showMenu : showHide.hideMenu}>
</EasyFlexCol>
here is working example for your refrence : https://stackblitz.com/edit/react-wj49ol
Use ternary operator when rendering.
class OverlayMenu extends Component {
render() {
const showHide= { // Assuming that strings below are valid CSS class names
showMenu: "overlay-menu-wrapper bg-color-dark overlay-menu-wrapper display-block",
hideMenu: "overlay-menu-wrapper bg-color-dark overlay-menu-wrapper"
};
let menuState = this.props.menuState
console.log(menuState)
return (
<EasyFlexCol className={menuState ? showHide.showMenu : showHide.hideMenu}>
</EasyFlexCol>
);
}
}
Alternatively you can compose style of <EasyFlexCol/> component dynamically
class OverlayMenu extends Component {
render() {
style={ display: 'block' }
let menuState = this.props.menuState
return (
<EasyFlexCol className={'some-default-class'} style={menuState ? style : {}}>
</EasyFlexCol>
);
}
}
Both example assume that <EasyFlexCol/> has either className property or style property.

How to dynamically change component's style?

To simplify the code, lets say I have to components (buttons). A parent and a child. When the parent is clicked, it sends property (number) to the child. This number helps select a specific color inside an array. Then, when I click on the child button, its color changes to the selected color. And that's where my problem is. I don't know how to update the component with the new color.
var arrayOfColors = ["#cd6155", "#af7ac5", "#5499c7", "#48c9b0", "#58d68d", "#f5b041", "#dc7633", "#EAECEE",
"#c0392b", "#9b59b6", "#2980b9", "#1abc9c", "#2ecc71", "#f39c12", "#d35400", "#D5D8DC",
"#a93226", "#884ea0", "#2471a3", "#17a589", "#28b463", "#d68910", "#ba4a00", "#ABB2B9",
"#922b21", "#76448a", "#1f618d", "#148f77", "#239b56", "#b9770e", "#a04000", "#808B96",
"#7b241c", "#633974", "#1a5276", "#117864", "#1d8348", "#9c640c", "#873600", "#566573",
"#641e16", "#512e5f", "#154360", "#0e6251", "#186a3b", "#7e5109", "#6e2c00", "#2C3E50"];
var color = null; //Initial global value that changes to a number selected from the parent component
Child component
class Square extends React.Component {
constructor(props){
super(props);
this.state = {value: null};
}
handleClick(){
this.setState({value: color, });
var myStyle = {background: "pink"};
myStyle.background = arrayOfColors[this.props.value];
boardColor = myStyle;
...................................................
This is where the update should happen (I suppose).
The button with style={boardColor}
...................................................
}
render() {
return (
<button className="square" onClick={() => this.handleClick()}>
{this.state.value}
</button>
);
}
}
I've see somewhere it was possible to change a component's color by changing its name. And then, in a Css file, have a different style for each name. The change occurs between two colors. I don't think that solution is adapted to my problem since I have more than 40 different colors
<!doctype html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
<title>Example</title>
</head>
<body>
<div id="app">
</div>
<script type="text/babel">
const SquareParent = () => {
return <Square parentColorNumber={11}/>
}
const arrayOfColors = ["#cd6155", "#af7ac5", "#5499c7", "#48c9b0", "#58d68d", "#f5b041", "#dc7633", "#EAECEE",
"#c0392b", "#9b59b6", "#2980b9", "#1abc9c", "#2ecc71", "#f39c12", "#d35400", "#D5D8DC",
"#a93226", "#884ea0", "#2471a3", "#17a589", "#28b463", "#d68910", "#ba4a00", "#ABB2B9",
"#922b21", "#76448a", "#1f618d", "#148f77", "#239b56", "#b9770e", "#a04000", "#808B96",
"#7b241c", "#633974", "#1a5276", "#117864", "#1d8348", "#9c640c", "#873600", "#566573",
"#641e16", "#512e5f", "#154360", "#0e6251", "#186a3b", "#7e5109", "#6e2c00", "#2C3E50"];
class Square extends React.Component {
constructor(props){
super(props);
this.state = { backgroundColor: null };
}
handleClick = () => {
const backgroundColor = arrayOfColors[this.props.parentColorNumber - 1];
this.setState({ backgroundColor });
}
render() {
const { backgroundColor } = this.state;
return (
<div>
<button className="square" style={{ backgroundColor }} onClick={ () => this.handleClick() }>
Current color - {this.state.backgroundColor || 'none'}
</button>
</div>
);
}
}
ReactDOM.render(<SquareParent/>, document.getElementById('app'))
</script>
</body>
</html>
I added as a parentColorNumber: 11. You can change it as you want.
You have a parent component that sends the data to it's child component.
class Square extends React.Component {
constructor(props){
super(props);
this.state = {value: null,backgroundColor:null};
}
handleClick(){
this.setState({value: color, });
var bg = arrayOfColors[this.props.value];
this.setState({backgroundColor:bg});
}
render() {
const { backgroundColor } = this.state;
return (
<button className="square" style={{backgroundColor}} onClick={() => this.handleClick()}>
{this.state.value}
</button>
);
}
}

React js: Accessing state of other components

I have a component built using the below code. The aim is to add a class on the card to highlight it when the button inside it is clicked. However, the below code works on the first click but doesn't work for the subsequent clicks.
I understood that I have to set the clicked state of other elements to false when I remove the class. How can this be done?
import React, { Component } from 'react';
import './PricingCard.css';
class PricingCard extends Component {
constructor(){
super();
this.state = {
clicked : false
}
}
makeSelection(){
let elems = document.getElementsByClassName('Card');
for(var i=0;i<elems.length;i++){
elems[i].classList.remove("active");
}
this.setState({clicked: true});
}
render() {
var activeClass = this.state.clicked ? 'active' : '';
return (
<div className= {"categoryItem Card " + this.props.planName + " " +activeClass}>
<div className="cardDetails">
<div> {this.props.planName} </div>
<div className="pricing"> {this.props.price} </div>
<button onClick={this.makeSelection.bind(this)} className="buttonPrimary"> Select this plan </button>
<div className="subtitle"> {this.props.footerText} </div>
</div>
</div>
);
}
}
export default PricingCard;
Wouldn't it be easier to have the logic in a parent component? Since it is "aware" of all the child Card components.
Have something like...
this.state = { selectedComponent: null };
onClick(card_id) {
this.setState({ selectedComponent: card_id });
}
...in render:
const cards = smth.map((card) =>
<Card onClick={this.onClick.bind(this, card.id)}
isActive={map.id === this.state.selectedComponent} />
Would this work?
Best way will be to lift lift the state up. Like this:
class PricingCardContainer extends React.Component {
constructor(props){
super(props);
this.state = {
selectedCard: NaN,
}
}
handleCardClick(selectedCard){ this.setState({ selectedCard }); }
render() {
return (
<div>{
this.props.dataArray.map((data, i) =>
<PricingCard
key={i}
className={this.state.selectedCard === i ? 'active': ''}
price={data.price}
onClick={() => this.handleCardClick(i)}
footerText={data.footerText}
planName={data.planName}
plan={data.plan}
/>
)
}</div>
)
}
}
const PricingCard = ({ className = '', planName, price, onClick, footerText }) => (
<div className= {`categoryItem Card ${planName} ${className}`}>
<div className="cardDetails">
<div> {planName} </div>
<div className="pricing"> {price} </div>
<button onClick={onClick} className="buttonPrimary"> Select this plan </button>
<div className="subtitle"> {footerText} </div>
</div>
</div>
);
export default PricingCard;
Although it would be better to use some data id than index value.

Add class to siblings when Component clicked in React

I'm working on building my portfolio using React.js. In one section, I have four components laid out in a grid. What I want to do achieve is when one component is clicked, a css class is added to the siblings of this component so that their opacity is reduced and only the clicked component remains. In jQuery, it would be something like $('.component').on('click', function(){ $(this).siblings.addClass('fadeAway')}). How can I achieve this effect? Here is my code, thanks in advance for any and all help!
class Parent extends Component{
constructor(){
super();
this.state = {fadeAway: false}
this.handleClick = this.handleClick.bind(this)
}
handleClick(){
//Add class to siblings
}
render(){
const array = ["Hello", "Hi", "How's it going", "Good Times"]
return(
array.map(function(obj, index){
<Child text={obj} key={index} onClick={() => this.handleClick} />
})
)
}
}
A working example for this problem could look something like this, with a marginally more complex initialization array:
class Parent extends Component{
constructor(){
super();
this.state = {
elements: [
{
id: "hello",
text: "Hello",
reduced: false,
},
{
id: "hi",
text: "Hi",
reduced: false,
}
{
id: "howsItGoing"
text: "How's it going",
reduced: false,
}
{
id: "goodTimes",
text: "Good Times",
reduced: false,
}
],
}
this.handleClick = this.handleClick.bind(this)
}
handleClick(e){
// copy elements from state
const elements = JSON.parse(JSON.stringify(elements));
const newElements = elements.map(element => {
if (element.id === e.target.id) {
element.reduced = false;
} else {
element.reduced = true;
}
});
this.setState({
elements: newElements,
});
}
render(){
return(
this.state.elements.map(function(obj, index){
<Child
id={obj.id}
text={obj.text}
reduced={obj.reduced}
key={index}
onClick={() => this.handleClick} />
});
);
}
}
Then you would just add a ternary, like so, to the Child component:
<Child
id={this.props.id}
className={this.props.reduced ? "reduced" : ""} />
This adds a bit more boilerplate than other examples, but it's extremely brittle to tie business logic to the text inside a component, and a stronger solution requires a stronger piece of identification, like an ID or class on the rendered DOM element. This solution also, if you so wish, easily allows you to expand your logic so that more than one element can remain at maximum opacity at once.
I would simply store in state index of selected item, and then pass fadeAway prop into Child component defined as
fadeAway={this.state.selectedIndex !== index}
After that you only need to set a fade-away class in Child based on this.prop.fadeAway and define necessary CSS rules.
Here is how it could look in your case:
class Parent extends React.Component{
constructor () {
super();
this.state = {selectedIndex: null}
}
handleClick (selectedIndex) {
this.setState({ selectedIndex })
}
render () {
const array = ["Hello", "Hi", "How's it going", "Good Times"]
return (
<div>
{array.map((obj, index) => {
const faded = this.state.selectedIndex && this.state.selectedIndex !== index
return <Child
text={obj}
fadeAway={faded}
key={index}
onClick={() => this.handleClick(index)} />
})}
</div>
)
}
}
class Child extends React.Component {
render () {
return (
<h2
onClick={this.props.onClick}
className={this.props.fadeAway ? 'fade-away' : ''}>
{this.props.text}
</h2>
)
}
}
ReactDOM.render(
<Parent />,
document.body
);
.fade-away {
opacity: 0.3;
}
<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>
You can achieve that using using a toggle variable :
handleClick(){
this.setState({fadeAway} => ({
fadeAway: ! fadeAway
)};
}
...
<Child
text={obj}
key={index}
onClick={() => this.handleClick}
className={this.state.fadeAway? 'class1' : 'class2'}/>
I perfer use state like currentWord to save the word was clicked in Parent component, presudo code is like below:
class Parent extends Component {
constructor(){
super();
this.state = {
fadeAway: false,
currentWord: ''
};
this.handleClick = this.handleClick.bind(this)
}
handleClick(currentWord){
this.setState({
currentWord: currentWord,
});
}
render(){
const array = ["Hello", "Hi", "How's it going", "Good Times"]
const currentWord = this.state.currentWord;
return(
array.map(function(obj, index){
<Child currentWord={currentWord} text={obj} key={index} onClick={() => this.handleClick} />
})
)
}
}
And in Child component
class Child extends Component {
// some other code
handleClick(e) {
this.props.handleClick(e.target.value);
}
render() {
const isSelected = this.props.text === this.props.currentWord;
// use isSelected to toggle className
<div
onClick={this.handleClick.bind(this)}
>{this.props.text}
</div>
}
}

hide/show clicking on another div

I want to hide/show list of elements when I click on button but it won't hide them and console.log of "shouldHide" is equal undefined.
function
showHideToggle(){
this.setState({shouldHide: true});
}
const { shouldHide} = this.props;
Div I want to hide
<div className={shouldHide ? 'hidden' : ''} >
<WeatherInfo />
</div>;
this is the div which is separate from one I'm trying to hide
<div onClick={(e) => {this.List(e);this.showHideToggle}}></div>
constructor
this.state = {
shouldHide: true
};
Your constructor should look like this:
constructor(props) {
super(props);
this.state = { shouldHide: true };
}
and your showhide should probably do this instead otherwise it won't toggle and will always be true
showHideToggle(){
this.setState({shouldHide: this.state.shouldHide ? false : true});
}
const { shouldHide} = this.props; should be const { shouldHide} = this.state in your render area
but <div className={this.state.shouldHide ? 'hidden' : ''} > should work as well given it's in the right area.

Categories