ReactJS: can not change style with changing state - reactjs

I'm new in ReactJS(in fact I'm learning), I've written a simple code to check the style changing but as my best knowledge when the state change in react it will reRender the component but when I did this it does not happen, so I tried forceUpdate() and this work but the style does not change again,
I've tried this before with a simple state and it worked but when I set my style in an object everything got screwed up, thanks for any help
class Check extends React.Component {
constructor(props) {
super(props);
this.state = {
sty: {
width: 200 + 'px',
backgroundColor: 'blue',
height: 200 + 'px', marginBottom: 20 + 'px'
}
}
this.update = this.update.bind(this);
}
update() {
let sty = this.state.sty;
sty.backgroundColor = 'red';
this.setState = ({
sty
})
this.forceUpdate();
}
render() {
console.error(this.state.sty['backgroundColor']);
return (
<div style={this.state.sty} onClick={this.update} id="checkBox" className="First">
<span>{this.props.children}</span>
</div>
)
}
}
ReactDOM.render(
<div>
<Check key={1}>1</Check>
<Check key={2}>2</Check>
<Check key={3}>3</Check>
<Check key={4}>4</Check>
</div>,
document.getElementById('container'))

not use =.Use this.setState({...})
https://reactjs.org/docs/react-component.html#setstate
class Check extends React.Component{
constructor(props) {
super(props);
this.state = {
sty : { width : 200 +'px',
backgroundColor : 'blue',
height: 200 + 'px', marginBottom : 20+'px' }
}
this.update = this.update.bind(this);
}
update(){
this.setState(prevState=>({sty:{...prevState.sty,backgroundColor:'red'}}))
}
render() {
console.error(this.state.sty['backgroundColor']);
return (
<div style={this.state.sty} onClick={this.update} id="checkBox" className="First">
<span>{this.props.children}</span>
</div> )
}
}
ReactDOM.render(
<div>
<Check key={1}>1</Check>
<Check key={2}>2</Check>
<Check key={3}>3</Check>
<Check key={4}>4</Check>
</div>, document.getElementById('container'))

In a React component, setState is a function, you have to call it to use it.
Here is a working example of your code :
class Check extends React.Component {
constructor(props) {
super(props);
this.state = {
sty: {
width: 200 + 'px',
backgroundColor: 'blue',
height: 200 + 'px', marginBottom: 20 + 'px'
}
}
}
update = () => {
this.setState({ sty: {
width: 200 + 'px',
backgroundColor: 'red',
height: 200 + 'px', marginBottom: 20 + 'px'
}
});
}
render() {
return (
<div style={this.state.sty} onClick={this.update} id="checkBox" className="First">
<span>{this.props.children}</span>
</div>
)
}
}
ReactDOM.render(
<div>
<Check key={1}>1</Check>
<Check key={2}>2</Check>
<Check key={3}>3</Check>
<Check key={4}>4</Check>
</div>,
document.getElementById('container'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.1.0/umd/react-dom.production.min.js"></script>
<div id='container'/>
A good practice would rather be to use CSS styling and make your components className vary based on his state

Related

React Select with avatar class component whats wrong here select not populating

Hi I had working select box with avatar on functional aporx. But I need build in functions to change selectbox properties like hidden: true/false, update option data function to add new option data to display selectbox with certain values on fly.
What I wrong here? Render part works as tested with functional version. The class factoring misses something as select box does not get info ether options and avatar to display and no width calculation happening.
Orginal functional code: https://codesandbox.io/s/react-select-longest-option-width-geunu?file=/src/App.js
Class based works but nodatin selectbox. Here is app.js with select.js fiddle: https://codesandbox.io/s/react-select-longest-option-width-forked-plqq0p?file=/src/Select.js
Source:
import React, { useRef } from "react";
import Select from "react-select";
class RtSelect extends React.Component {
constructor(props) {
super();
this.state = {
info: props.info,
options: props.options,
hidden: props.hidden,
menuIsOpen: false,
menuWidth: "",
IsCalculatingWidth: false
};
this.selectRef = React.createRef();
this.onMenuOpen = this.onMenuOpen.bind(this);
}
componentDidMount() {
if (!this.menuWidth && !this.isCalculatingWidth) {
setTimeout(() => {
this.setState({IsCalculatingWidth: true});
// setIsOpen doesn't trigger onOpenMenu, so calling internal method
this.selectRef.current.select.openMenu();
this.setState({MenuIsOpen: true});
}, 1);
}
}
onMenuOpen() {
if (!this.menuWidth && this.isCalculatingWidth) {
setTimeout(() => {
const width = this.selectRef.current.select.menuListRef.getBoundingClientRect()
.width;
this.setState({menuWidth: width});
this.setState({IsCalculatingWidth: false});
// setting isMenuOpen to undefined and closing menu
this.selectRef.current.select.onMenuClose();
this.setState({MenuIsOpen: true});
}, 1);
}
}
styles = {
menu: (css) => ({
...css,
width: "auto",
...(this.isCalculatingWidth && { height: 0, visibility: "hidden" })
}),
control: (css) => ({ ...css, display: "inline-flex " }),
valueContainer: (css) => ({
...css,
...(this.menuWidth && { width: this.menuWidth })
})
};
setData (props) {
this.setState({
info: props.info,
options: props.options,
hidden: props.hidden
})
}
render() {
return (
<div style={{ display: "flex" }}>
<div style={{ margin: "8px" }}>{this.info}</div>
<div>
<Select
ref={this.selectRef}
onMenuOpen={this.onMenuOpen}
options={this.options}
menuIsOpen={this.menuIsOpen}
styles={this.styles}
isDisabled={this.hidden}
formatOptionLabel={(options) => (
<div className="select-option" style={{ display: "flex" }}>
<div style={{ display: "inline", verticalAlign: "center" }}>
<img src={options.avatar} width="30px" alt="Avatar" />
</div>
<div style={{ display: "inline", marginLeft: "10px" }}>
<span>{options.label}</span>
</div>
</div>
)}
/>
</div>
</div>
);
}
}
export default RtSelect;
Got it working!
I had removed "undefined" from onOpen setState function. I compared those 2 fiddles and finally got it working.
// setting isMenuOpen to undefined and closing menu
this.selectRef.current.select.onMenuClose();
this.setState({MenuIsOpen: undefined});

function uses this.state and pass it to another component

hey guys simple question. i have a class component, with a state with two colors inside.
i want to create a onClick function, that when you click it, it shows 2 divs with backgroundColors from this.state.
and the button MOST be on the parent
here the code
class Parent extends React.Component{
constructor(props){
super(props);
this.state = {
color1: "#38306b",
color2: "#fff285"
}
saveColors() = {
// thats the part i dont get.
render(){
return(
<Child />
<button onClick={() => saveColors()}>save</button>
)
class Child extends React.Component{
render(){
return(
//those divs need to appear when we click the button with saveColors().
<div style={{backgroundColor: color1 from Parent's state}}></div>
<div style={{backgroundColor: color2 from Parent's state}}></div>
)
can i put this.state.color1 into a var and use it in the child component? or should i use return?? or something else??
You need to state in Parent to check button clicked. And pass value from Parent to Child:
this.state = {
color1: "#38306b",
color2: "#fff285",
isClicked: false,
}
saveColors = () => {
this.setState({isClicked: true})
}
<Child color1={this.state.color1} color2={this.state.color2} isClicked={this.state.isClicked} />
And on the `Child:
return (
...
{this.props.isClicked && (
<>
<div style={{backgroundColor: this.props.color1}}></div>
<div style={{backgroundColor: this.props.color2}}></div>
</>
)}
)
You can just pass the state to Child as a props
class Main extends React.Component {
constructor(props) {
super(props);
this.state = {
color1: "#38306b",
color2: "#fff285"
}
}
saveColors() {
}
render() {
return (
<div style={{ flex: 1, backgroundColor: 'red' }}>
<Child color={this.state} />
<button onClick={() => this.saveColors()}>save</button>
</div>
)
}
}
class Child extends React.Component {
render() {
return (
<>
<div style={{
flex: 1,
backgroundColor: this.props.color.color1,
height: 400
}}>
DIV1
</div>
<div style={{
flex: 1,
backgroundColor: this.props.color.color2,
height: 400
}}>
DIV2
</div>
</>
)
}
}
And if you want to change the color when the button clicked just change the state using setState
saveColors() {
this.setState({
color1: 'blue',
color2: 'red'
})
}

I passed a change event to the child component, but the state of the parent does not change

At ReactJs I passed a change event to the child component, but I can't change the parent's state to show this value that came from the child.
I give a setState there at the parent, with the correct digit that comes from it, however the state does not change. Any help?
This father component:
import React from 'react';
import SnippetInput from './SnippetInput';
import BlockedInput from './BlockedInput';
export default class QuantityBlockedValue extends React.Component{
constructor(props){
super(props);
this.state = {
valorinput: 1,
valorbloqueado: 1
}
this.handleChangeSnippet = this.handleChangeSnippet.bind(this); //Event to passing to children
}
componentDidMount(){
let precoitem = (this.props.precoitem) ? this.props.precoitem : 1;
this.setState({valorbloqueado: this.state.valorinput * precoitem});
}
//Passing event change to children and execute here
handleChangeSnippet(event){
let digito = event.target.value;
let digitoInt = parseInt(digito);
if(digitoInt > 0){
//digitoInt return correc number from children, but valorinput state dont update! why??
this.setState({valorinput: digitoInt});
}
}
render(){
return(
<div>
<div className="center">
<h4>Quantity</h4>
<SnippetInput valorinput={this.state.valorinput} handleChange={this.handleChangeSnippet} />
<h4>Value</h4>
<BlockedInput valorbloqueado={this.state.valorbloqueado}/>
</div>
</div>
);
}
}
The children component:
import React from "react";
export default class SnippetInput extends React.Component{
constructor(props){
super(props);
this.state = {
valorinput : (this.props.valorinput) ? this.props.valorinput : 1
}
// this.handleChange = this.handleChange.bind(this);
this.handleAumentar = this.handleAumentar.bind(this);
this.handleDiminuir = this.handleDiminuir.bind(this);
}
handleAumentar(){
let digitoAumentado = this.state.valorinput + 1;
this.setState({valorinput: digitoAumentado});
}
handleDiminuir(){
let digito = this.state.valorinput;
if(digito > 1){
let digitoDiminuido = this.state.valorinput - 1;
this.setState({valorinput: digitoDiminuido});
}
}
render(){
let stylecorbotaodiminuir = "#F44336";
let stylecorbotaoaumentar = "#009688";
if(this.props.corBotaoDiminuir){
stylecorbotaodiminuir = this.props.corBotaoDiminuir;
}
if(this.props.corBotaoAumentar){
stylecorbotaoaumentar = this.props.corBotaoAumentar;
}
const stylebotaodiminuir = {
display: "inline-block",
width: "50px",
height: "50px",
backgroundColor: stylecorbotaodiminuir,
textAlign: "center"
};
const stylebotaoaumentar = {
display: "inline-block",
width: "50px",
height: "50px",
backgroundColor: stylecorbotaoaumentar,
textAlign: "center"
};
return (
<div>
<div>
<div id="diminuir" className="noTextSelect" style={stylebotaodiminuir} onClick={this.handleDiminuir}>
<span style={{fontSize: "30px", padding: "10px"}}>-</span>
</div>
<input style={{"width":"150px","textAlign": "center"}} type="text" value={this.state.valorinput} onChange={this.props.handleChange}/>
<div id="aumentar" className="noTextSelect" style={stylebotaoaumentar} onClick={this.handleAumentar}>
<span style={{fontSize: "30px", padding: "10px"}}>+</span>
</div>
</div>
</div>
);
}
}

Rotation control in NavigationControl doesn't work in react-map-gl

I am having an issue with the rotation control not working for react-map-gl. The map renders without and issue and the zoom in/out controls work fine but the rotation control doesn't do anything. I've looked through the documentation but I can't see an issue. Here is my code:
import React, { Component } from 'react';
import ReactMapGL, { NavigationControl } from 'react-map-gl';
import styles from './styles/ViewMap.module.scss'
import mapPin from './img/mapPin.png'
export default class Map extends Component {
constructor(props) {
super(props);
this.state = {
viewport: {
width: '100%',
height: '100%',
latitude: 37.7577,
longitude: -122.4376,
zoom: 12
},
mapStyle: "streets-v9",
style: 'mapbox://styles/mapbox/',
};
this.mapStyle_onChange = this.mapStyle_onChange.bind(this);
}
componentDidMount() {
console.log("DIDMOUNT");
}
mapStyle_onChange(e) {
this.setState({ mapStyle: e.currentTarget.value, latitude: 0, longitude: 0 });
}
render() {
return (
<div className={styles.parentMapContainer}>
<div ref={el => this.mapContainer = el} className={styles.mapContainer}>
<div className={styles.mapStyleRow}>
<input type="radio" id="rdStreets" value="streets-v9" onChange={this.mapStyle_onChange} className={styles.mapStyleRadio} name="mapStyle" checked={this.state.mapStyle === "streets-v9"} />
<div className={styles.mapStyleLabel}>Street</div>
<input type="radio" id="rdSatellite" value="satellite-v9" onChange={this.mapStyle_onChange} className={styles.mapStyleRadio} name="mapStyle" checked={this.state.mapStyle === "satellite-v9"} /><div className={styles.mapStyleLabel}>Satellite</div>
</div>
<ReactMapGL
mapStyle={this.state.style + this.state.mapStyle}
mapboxApiAccessToken='pk.eyJ1INybW91bTJsbDF3dyJ9.vWoue-jEOJBbffqeMZDIEw'
{...this.state.viewport}
onViewportChange={(viewport) => this.setState({ viewport })}>
<div style={{ position: 'absolute', right: 0 }}>
<NavigationControl onViewportChange={(viewport) => this.setState({ viewport })} />
</div>
</ReactMapGL>
</div>
</div>
);
}
}

How do I add an image to the DOM after another image has loaded?

I want to make sure images are loaded in the right order: first the primary image, then the secondary image. My plan is to inject the secondaryImage once the primary image is done.
class HoverImage extends Component {
constructor (props) {
super(props)
this.state = { secondaryImage: null }
}
primaryImageLoaded () {
//here I would like inject <img className='img-responsive' src={stripUrl(secondaryImage)} /> before primaryImage
}
render () {
const primaryImage = this.props.primaryImage
const secondaryImage = this.props.secondaryImage
if (secondaryImage) {
return (
<div style={{position: 'relative'}}>
<img
className='img-responsive'
src={stripUrl(primaryImage)}
onLoad={this.primaryImageLoaded.bind(this)}
style={{
':hover': {
opacity: 0
},
position: 'absolute',
top: 0}}
/>
</div>
)
}
}
other solutions that create the same effect are fine too!
Try this:
class HoverImage extends Component {
constructor (props) {
super(props)
this.state = {
secondaryImage: null,
showSecondaryImage: false,
}
}
primaryImageLoaded () {
this.setState({showSecondaryImage: true});
}
render () {
const primaryImage = this.props.primaryImage;
const secondaryImage = this.props.secondaryImage;
secondaryImage ?
return (
<div style={{position: 'relative'}}>
{this.state.showSecondaryImage ?
<img className='img-responsive' src={stripUrl(secondaryImage)} />
: <div/>}
<img
className='img-responsive'
src={stripUrl(primaryImage)}
onLoad={this.primaryImageLoaded.bind(this)}
style={{
':hover': {
opacity: 0
},
position: 'absolute',
top: 0
}}
/>
</div>
)
: return <div/>
}
}
jsfiddle link: http://jsfiddle.net/d7hwzapc/
class HoverImage extends Component {
constructor (props) {
super(props)
this.state = {
firstImageLoaded: false,
};
}
componentDidMount() {
this.setState({ firstImageLoaded: true });
}
loadSecondImage() {
if(this.state.firstImageLoaded) {
return (<img
className='img-responsive'
src={stripUrl(this.props.secondaryImage)}
/>);
}
}
render () {
return (
<div style={{position: 'relative'}}>
<img
className='img-responsive'
src={stripUrl(this.props.primaryImage)}
onLoad={this.setState({ firstImageLoaded: true })}
style={{
':hover': {
opacity: 0
},
position: 'absolute',
top: 0}}
/>
{this.loadSecondImage()}
</div>
)
}
When the initial mount is done, it will set a flag in the state which will trigger a re-render.
Hope that helps!
ps: this answer is in no way perfect but should get what you wanted done.

Resources