I can't get refs working. I want to render several columns and then render items that are placed over the right column. For example, declared items: const items = [0, 2, 5] should be rendered over the grid like that (assuming that first column has index 0):
I want to use refs on columns for getting column positions (using getBoundingClientRect() just for the idea) but my columnsRefs[index].current is null even though refs are assigned in componentDidMount as it's recommended. Here is my code:
import * as React from 'react';
export const GridColumn = (props: {forwardedRef?: any }) => (
<div style={{borderRight: "1px solid #ababab", width: "20px", height: "200px"}} ref={props.forwardedRef}></div>
);
interface GridProps {
}
export class Grid extends React.Component<GridProps, any> {
public constructor(props: GridProps) {
super(props);
this.state = {
columns: []
}
}
private columnRefs = new Array<React.RefObject<HTMLDivElement>>();
public componentDidMount(){
// setup the columns with refs
const columnIds = [0, 1, 2, 3, 4, 5, 6, 7];
const columns = columnIds.map(id => {
const ref = React.createRef<HTMLDivElement>();
this.columnRefs.push(ref);
return (<GridColumn forwardedRef={ref}/>)
});
this.setState({columns: columns});
}
public render() {
// setup the items
const items = [
0, 2, 5
]
let elements = items.map(item => {
if(this.columnRefs[item] && this.columnRefs[item].current) {
return (
<div style={{backgroundColor: "blue",
opacity: 0.5,
position: "absolute",
width: "10px",
height: "20px",
left: `${this.columnRefs[item].current.getBoundingClientRect().left}px`,
top: "0"}}>
</div>);
}
else {
return undefined;
}
});
return (
<div style={{width: "500px", height: "200px", position: "relative"}}>
{elements}
<div style={{display: "flex"}}>
{this.state.columns}
</div>
</div>);
}
}
What do I do wrong so that the condition in render if(this.columnRefs[item] && this.columnRefs[item].current) is all the time false?
You should not store your rendered components in state. State is for data you want to transform into markup. Here is modified code with annotations:
// Now component properly forwards ref
const GridColumn = React.forwardRef((props, ref) => (
<div
style={{ borderRight: "1px solid #ababab", width: "20px", height: "200px" }}
ref={ref}
{...props}
></div>
));
class Grid extends React.Component {
constructor(props) {
super(props);
this.state = {
columns: [1,2,3,4,5,6,7,8,9],
rendered: false
};
}
// When you want to use collection of refs, you can set up your own storage for them
// I use Set because it will prevent duplicates
// It is important that when component will be removed it's ref will turn into `null`, so you will have to check if your div still exists
columnRefs = new Set();
componentDidUpdate() {
// you will see your refs set in console on each render
console.debug(this.columnRefs);
}
componentDidMount() {
// You need to rerender to render something from refs
this.setState({rendered: true});
}
render() {
const items = [0, 2, 5];
let elements = items.map((item) => {
// turn set into array and filter out null
let refArray = [...this.columnRefs].filter(Boolean);
if (refArray[item]) {
return (
<div
key={item}
style={{
backgroundColor: "blue",
opacity: 0.5,
position: "absolute",
width: "10px",
height: "20px",
left: `${refArray[item].getBoundingClientRect().left}px`,
top: "0",
}}
></div>
);
} else {
return undefined;
}
});
return (
<div style={{ width: "500px", height: "200px", position: "relative" }}>
{elements}
<div style={{ display: "flex" }}>
{/* We use here ref callback to store forwarded ref into out set */}
{this.state.columns.map((item) => (
<GridColumn key={item} ref={(ref) => this.columnRefs.add(ref)} />
))}
</div>
</div>
);
}
}
What to read:
callback refs
forwarding refs
Set
Example
Reproducible and partially fixed example: https://jsfiddle.net/moL1sbzj/
I'm not sure if refs are needed at all
Use left:
left: item * 20 + 'px',
it's cheaper than .current.getBoundingClientRect().left
result:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react#17/umd/react.development.js" crossorigin ></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.development.js" crossorigin ></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script type="text/babel">
const {useEffect, Fragment, useState} = React;
const GridColumn = (props) => (
<div
style={{ borderRight: "1px solid #ababab", width: "20px", height: "200px" }}
{...props}
></div>
);
class Grid extends React.Component {
constructor(props) {
super(props);
this.state = {
columns: [1, 2, 3, 4, 5, 6, 7, 8, 9],
rendered: false
};
}
componentDidUpdate() {
// you will see your refs set in console on each render
// console.debug(this.columnRefs);
}
componentDidMount() {
// You need to rerender to render something from refs
this.setState({ rendered: true });
}
render() {
const items = [0, 2, 5];
return (
<div
style={{
width: "500px",
height: "200px",
position: "relative"
}}
>
<div style={{ display: "flex" }}>
{this.state.columns.map((item, index) => (
<GridColumn key={item}>
{items.includes(index) && (
<div
style={{
backgroundColor: "blue",
opacity: 0.5,
width: "10px",
height: "20px"
}}
></div>
)}
</GridColumn>
))}
</div>
</div>
);
}
}
ReactDOM.render(<Grid />, document.getElementById("root"));
</script>
</body>
</html>
Multicolumn example:
getWidth function was added for calculate fill (width):
getWidth = (arr, index) => {
return arr.includes(index + 1) ? 20 : 10;
};
using this:
width: this.getWidth(items, index) + "px",
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react#17/umd/react.development.js" crossorigin ></script>
<script src="https://unpkg.com/react-dom#17/umd/react-dom.development.js" crossorigin ></script>
<script src="https://unpkg.com/babel-standalone#6/babel.min.js"></script>
<script type="text/babel">
const {useEffect, Fragment, useState} = React;
const GridColumn = (props) => (
<div
style={{ borderRight: "1px solid #ababab", width: "20px", height: "200px" }}
{...props}
></div>
);
class Grid extends React.Component {
constructor(props) {
super(props);
this.state = {
columns: [1, 2, 3, 4, 5, 6, 7, 8, 9],
rendered: false
};
}
componentDidUpdate() {
// you will see your refs set in console on each render
// console.debug(this.columnRefs);
}
componentDidMount() {
// You need to rerender to render something from refs
this.setState({ rendered: true });
}
getWidth = (arr, index) => {
return arr.includes(index + 1) ? 20 : 10;
};
render() {
const items = [0,1, 2, 5];
return (
<div
style={{
width: "500px",
height: "200px",
position: "relative"
}}
>
<div style={{ display: "flex" }}>
{this.state.columns.map((item, index) => (
<GridColumn key={item}>
{items.includes(index) && (
<div
style={{
backgroundColor: "blue",
opacity: 0.5,
width: this.getWidth(items, index) + "px",
height: "20px"
}}
></div>
)}
</GridColumn>
))}
</div>
</div>
);
}
}
ReactDOM.render(<Grid />, document.getElementById("root"));
</script>
</body>
</html>
for achieve this effect (no vertical lines) use style:
.afterFull::after {
content: "";
display: block;
position: relative;
left: 1px;
height: 20px;
border-right: 1px solid;
border-color: var(--color);
}
in code:
<div
className="afterFull"
style={{
backgroundColor: "blue",
opacity: 0.5,
width: this.getWidth(items, index) + 0 + "px",
height: "20px",
"--color": "rgba(0, 0, 255, 0.5)"
}}
/>
Related
I am trying to pass function as prop. I did this before but now with the same logic it is giving me error (this.props.functionName is not a function).
I have a child (Navbar) and a parent component(MainComponent). I want to send a input value from Navbar to MainComponet and set it to the state value in parent Component.
Parent Component
import React ,{Component}from 'react'
import Navbar from '../Presentational/Navbar'
class Main extends Component{
constructor(props){
super(props)
this.state = {
searchItem: ''
}
}
GetSearchItem(search){
this.setState({searchItem:search})
}
render(){
return(
<div className = 'container'>
<div className = 'row'>
<div className = 'col-12 mt-1'>
<Navbar onChange = {(search)=>this.GetSearchItem(search)}></Navbar>
</div>
</div>
<div className = 'row'>
<div className = 'col-3'>
<h3>{this.state.searchItem}</h3>
</div>
</div>
</div>
)
}
}
export default Main
Child Component (Navbar)
import React,{Component} from 'react'
import {AppBar,Toolbar,IconButton,Typography,InputBase} from '#material-ui/core'
import MenuIcon from '#material-ui/icons/Menu';
import SearchIcon from '#material-ui/icons/Search';
import {fade , makeStyles} from '#material-ui/core/styles'
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
display: 'none',
[theme.breakpoints.up('sm')]: {
display: 'block',
},
},
search: {
position: 'relative',
borderRadius: theme.shape.borderRadius,
backgroundColor: fade(theme.palette.common.white, 0.15),
'&:hover': {
backgroundColor: fade(theme.palette.common.white, 0.25),
},
marginLeft: 0,
width: '100%',
[theme.breakpoints.up('sm')]: {
marginLeft: theme.spacing(1),
width: 'auto',
},
},
searchIcon: {
padding: theme.spacing(0, 2),
height: '100%',
position: 'absolute',
pointerEvents: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
inputRoot: {
color: 'inherit',
},
inputInput: {
padding: theme.spacing(1, 1, 1, 0),
// vertical padding + font size from searchIcon
paddingLeft: `calc(1em + ${theme.spacing(4)}px)`,
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('sm')]: {
width: '12ch',
'&:focus': {
width: '20ch',
},
},
},
}));
class Navbar extends Component{
render(){
const classes = this.props.classes;;
return(
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<IconButton
edge="start"
className={classes.menuButton}
color="inherit"
aria-label="open drawer"
>
<MenuIcon />
</IconButton>
<Typography className={classes.title} variant="h6" noWrap>
Pizaa Valley
</Typography>
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<InputBase
placeholder="Search…"
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
inputProps={{ 'aria-label': 'search' }}
onChange={(event)=>this.props.onChange(event.target.value)}
/>
</div>
</Toolbar>
</AppBar>
</div>
)
}
}
export default () => {
const classes = useStyles();
return (
<Navbar classes={classes} />
)
}
The problem is that you have two Navbar types. You first have the class component created using class Navbar. And second you have the following functional component defined here:
export default () => {
const classes = useStyles();
return (
<Navbar classes={classes} />
)
}
When you do
import Navbar from '../Presentational/Navbar'
<Navbar onChange = {(search)=>this.GetSearchItem(search)}></Navbar>
The onChange prop is correctly given to the functional component, but is never passed along to the class-based component. You can fix this by replacing your functional component with the below code:
export default props => {
const classes = useStyles();
return (
// using the "spread operator", we pass along all the props given
// to the functional component, so the class-based component can
// also access these
<Navbar {...props} classes={classes} />
)
}
you've done everything correctly except change this:
GetSearchItem(search){
this.setState({searchItem:search})
}
to
GetSearchItem = (search) => {
this.setState({searchItem:search})
}
as an arrow function it has access to the scope above
Try with the following:-
In your parent component modified the below line:-
<Navbar onChangeCallBack = {(search)=>this.GetSearchItem(search)}></Navbar>
In your child Navbar component only modified the below line:-
onChange={(event)=>this.props.onChangeCallBack(event.target.value)}
I have a parent React.js component, passing a state and a setter to a child component.
Every time the child component use the setter, the child component is unmounted & remounted.
I'm new to react and I don't understand what is happening.
const useState = React.useState;
class MyComponnent extends React.Component {
intervalID = null;
componentDidMount() {
console.log("MOUNTING");
this.intervalID = setInterval(() => {
this.props.setA({ a: this.props.a.a + 1 });
}, 1000);
}
componentWillUnmount() {
clearInterval(this.intervalID);
}
render = () => {
return (
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
flexDirection: "column"
}}
>
<div
style={{
flexDirection: "row",
display: "flex",
justifyContent: "center",
alignItems: "center",
marginTop: "30px"
}}
>
{this.props.a.a}
</div>
</div>
);
};
}
function App() {
const [activeStep] = useState(0);
const [a, setA] = useState({ a: 0 });
// eslint-disable-next-line react/no-multi-comp
function StepPage() {
if (0 === 0) {
return <MyComponnent a={a} setA={setA} />;
} else {
return <MyComponnent />;
}
}
return (
<div>
<StepPage />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
.App {
font-family: sans-serif;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<div id="root"></div>
The problem is that your are creating a new instance of your component by defining StepPage inside a render function.
You can refactor your StepPage component so it will be defined outside of render method,
function StepPage({ setA, a}) {
if (0 === 0) {
return <MyComponnent a={a} setA={setA} />;
} else {
return <MyComponnent />;
}
}
export default function App() {
const [activeStep] = useState(0);
const [a, setA] = useState({ a: 0 });
return (
<div>
<StepPage a={a} setA={setA} />
</div>
);
}
StepPage in your example is re-defined every time App renders.
Calling the function normally instead of using it as a React component alleviates the issue:
return (
<div>
{StepPage()}
</div>
);
const useState = React.useState;
class MyComponnent extends React.Component {
intervalID = null;
componentDidMount() {
console.log("MOUNTING");
this.intervalID = setInterval(() => {
this.props.setA({ a: this.props.a.a + 1 });
}, 1000);
}
componentWillUnmount() {
clearInterval(this.intervalID);
}
render = () => {
return (
<div
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
flexDirection: "column"
}}
>
<div
style={{
flexDirection: "row",
display: "flex",
justifyContent: "center",
alignItems: "center",
marginTop: "30px"
}}
>
{this.props.a.a}
</div>
</div>
);
};
}
function App() {
const [activeStep] = useState(0);
const [a, setA] = useState({ a: 0 });
// eslint-disable-next-line react/no-multi-comp
function StepPage() {
if (0 === 0) {
return <MyComponnent a={a} setA={setA} />;
} else {
return <MyComponnent />;
}
}
return (
<div>
{StepPage()}
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
.App {
font-family: sans-serif;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<div id="root"></div>
tl;dr: I'm finding that consecutive elements on my page with position: relative are overlapping, and really don't understand why.
Details: I'm trying to write a re-usable React component SlidePair that allows you to toggle between two other components with a slide animation, passing data between them. I'm using react-reveal for the animation, and positioning the elements at the same place in the page, so the exit of one accompanies the entry of the other. To make the divs overlap I followed the approach of this SO question.
My code, in the context of an App.js file from create-react-app, is below. You see that in the main App component I want to stack two SlidePair elements, which turn out to overlap instead. Everything else are just some example components for me to plug in; I've only included them for the sake of anyone who just wants to copy and paste the whole thing to get it running.
import React, {Component} from 'react';
import Slide from 'react-reveal/Slide';
class RedBox extends Component {
constructor(props){
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
text: props.text
}
}
handleChange(event) {
this.setState({text: event.target.value});
}
render(){
const { toggleState, text, style} = this.props;
return(
<div style={style}
onClick={()=>{console.log('red clicked'); toggleState({text: this.state.text})}}>
<input onChange={this.handleChange}
type="text" value={this.state.text}
onClick={(event)=>{event.stopPropagation()}}
style={{zIndex: '999'}}
/>
{ text }
</div>
);
}
}
const BlueBox = ({toggleState, passedProps, style })=> {
return (
<div onClick={toggleState} style={style}>
{ passedProps.text }
</div>
);
};
class MouseTracker extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(event) {
const coords = {
x: event.clientX,
y: event.clientY
};
this.props.toggleState(coords);
}
render() {
return (
<div style={{ height: '100px' }} onClick={this.handleClick}>
<h1>Click me!</h1>
</div>
);
}
}
const MouseInformer = ({toggleState, passedProps}) => (
<div>
You clicked {passedProps.x}, {passedProps.y}!
<button onClick={toggleState}>Go Back</button>
</div>
);
class SlidePair extends Component {
constructor(props){
super(props);
this.state = { left: true, passedProps: {}};
this.toggleState = this.toggleState.bind(this);
}
toggleState(passedProps){
const left = !this.state.left;
console.log(`Toggling left to ${left}`);
this.setState({ left, passedProps });
}
render(){
const {left, passedProps } = this.state;
return(
<div style={{position: 'relative'}}>
<Slide left when={left} >
<div style={ {position: 'absolute', top: '0px', right: '0px', width: '100%', zIndex: left ? '998' : -1 }}>
{this.props.renderLeft(this.toggleState, passedProps)}
</div>
</Slide>
<Slide right when={!left}>
<div style={{position: 'absolute', top: '0px', right: '0px', width: '100%', zIndex: left ? -1 : 1}}>
{ this.props.renderRight(this.toggleState, passedProps) }
</div>
</Slide>
</div>
)
}
}
class App extends Component {
render(){
const redBox = (toggleState, passedProps)=>(
<RedBox toggleState={toggleState}
style={{width: '100%', border: '5px solid red', height: '100px'}}/>
);
const blueBox = (toggleState, passedProps) => (
<BlueBox
toggleState={toggleState}
passedProps={passedProps}
style={{width: '100%', border: '5px solid blue', height: '100px'}}
/>
);
const mouseTracker = (toggleState, passedProps) => (
<MouseTracker toggleState={toggleState} passedProps={passedProps} style={{top: '300px'}}/>
);
const mouseInformer = (toggleState, passedProps) => (
<MouseInformer toggleState={toggleState} passedProps={passedProps} style={{top: '300px'}}/>
);
return (
<div className="App">
<SlidePair renderLeft={redBox} renderRight={blueBox}/>
<br/>
<SlidePair renderLeft={mouseTracker} renderRight={mouseInformer} />
</div>
);
}
}
export default App;
Thanks in advance for any help.
var img;
var dateFormat = require('dateformat');
var count;
let arrayIMG = []
var storage = firebase.storage();
var storeRef = storage.ref('images/')
const config = {
...
};
if (!firebase.apps.length) {
firebase.initializeApp(config);
}
const subContStyle = {
width: '450px',
height: '60px',
marginLeft: '90px'
};
const photoStyle = {
width: '400px',
height: '200px'
};
const MainFeedStyle = {
marginLeft: '40px',
width: '1050px',
height: '500px',
overflowY: 'auto'
}
const footer = {
marginTop: '80px'
};
const h2Style = {
marginTop: '60px',
marginLeft: '100px',
fontstyle: 'Century Gothic'
};
const button_style = {
marginLeft: "6px"
};
const uploadBtn = {
marginRight: "5px"
};
const styles = {
card: {
maxWidth: 345,
},
media: {
height: 140,
},
};
const headStyle = {
height: '530px',
overflowY: 'auto',
width: '1140px',
marginTop: '-130px',
};
const perDivStyle = {
width: '60%',
height: '20%',
marginLeft: '200px'
}
class Feed extends Component {
constructor(props) {
super(props);
// this.state = {}
this.state = {
arrayIMGS: arrayIMG,
news: [],
title: [],
dateCreated: []
};
}
componentDidMount() {
var that = this
firebase.database().ref('/IMAHE').on("child_added", function (arrayIMG) {
let newData = [...that.state.arrayIMGS]
var yeah = dateFormat(arrayIMG.val().createdAt,"dddd, mmmm dS, yyyy, h:MM:ss TT")
newData.push(arrayIMG.val().url)
that.setState({ arrayIMGS: newData})
})
}
render() {
return(
<div>
<div style={headStyle}>
<div style={perDivStyle}>
{this.state.arrayIMGS.map((e) =>
{ return (
<ListGroup>
<ListGroupItem >
<Card>
{/*{alert("URL: "+e)}*/}
{/*{alert("Indexes: "+index)}*/}
<CardImg top width="50%" src={e} alt="Card image cap" />
<CardBody>
<CardTitle>{e.title}</CardTitle>
<CardText>This is a wider card with supporting text below as a natural lead-in to additional content. This content is a little bit longer.</CardText>
<CardText>
<small className="text-muted">{this.state.dateCreated}</small>
</CardText>
</CardBody>
</Card>
</ListGroupItem>
</ListGroup>
)}
)}
</div>
<div style={footer}>
</div>
</div>
</div>
);
}
}
export default Feed;
components (chartJS and mapping images from firebase) not working well in first load unless you reload the page. The function of this module is to show user all the images that are being uploaded by other users, so it is expected to load all the images once the page is loaded, but in my case it's not working that way, I have to reload the page to make it work
I think making same call in componentDidUpdate should work but be aware it will trigger stackoverflow so you should add condition to stop setState.
I have a parent and child component there is a button in parent component on Clicking that button it should send a Props -"red" so the child should receive the red and change its background color as red. Below my code is there
jsfiddle.net/t1ru6oyz/3/
Child
import React from "react";
import ReactDOM from "react-dom";
const childContainer = {
border: "0px solid #000",
width: "300px",
height: "300px",
textAlign: "middle",
margin: "0 auto",
marginTop: "60px"
};
const Child = props => {
return (
<div
style={{
backgroundColor: props.color
}}
/>
);
};
export default Child;
Parent
import React, { Component } from "react";
import "./App.css";
import Child from "./child";
const parentContainer = {
border: "10px solid #000",
width: "500px",
height: "500px",
margin: "20px",
textAlign: "middle"
};
class App extends Component {
constructor() {
super();
this.state = {
currentColor: "red"
};
}
componentDidMount() {
this.setState({
currectColor: "green"
});
}
changeColor = () => {
this.setState({
currectColor: "blue"
});
};
render() {
console.log("in render", this.state);
return (
<div style={parentContainer}>
<button onClick={this.changeColor}>Blue</button>
<p>{this.state.name}</p>
<Child color={this.state.currentColor} />
</div>
);
}
}
export default App;
You have a few typos there in your parent component like currectColor, just fix those first. Then, you can add the backgroundColor property to your childContainer if there is prop by checking it.
const parentContainer = {
border: "10px solid #000",
width: "500px",
height: "500px",
margin: "20px",
textAlign: "middle"
};
class App extends React.Component {
constructor() {
super();
this.state = {
currentColor: "red"
};
}
componentDidMount() {
this.setState({
currentColor: "green"
});
}
changeColor = () => {
this.setState({
currentColor: "blue"
});
};
render() {
return (
<div style={parentContainer}>
<button onClick={this.changeColor}>Blue</button>
<p>{this.state.name}</p>
<Child color={this.state.currentColor} />
</div>
);
}
}
const Child = props => {
let childContainer = {
border: "0px solid #000",
width: "300px",
height: "300px",
textAlign: "middle",
margin: "0 auto",
marginTop: "60px"
};
if ( props.color ) {
childContainer = { ...childContainer, backgroundColor: props.color }
}
return (
<div
style={childContainer}
/>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
<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>
I have created my own components, but you can apply this logic.
class Child extends React.Component {
constructor(props) {
super(props);
}
render() {
return ( <
h1 style = {
{
backgroundColor: this.props.color
}
} > hello < /h1>
)
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
color: ''
}
}
handleClick = () => {
this.setState({
color: 'red'
})
}
render() {
return ( <
div >
<
Child color = {
this.state.color
}
/> <
button onClick = {
this.handleClick
} > change Child color < /button> < /
div >
)
}
}
ReactDOM.render( <
Parent / > ,
document.getElementById("root")
);
<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>
You need change in App component. Keep currentColor to blue and change it to red in changeColor function but you are doing it in reverse
Try with below code
const parentContainer = {
border: "10px solid #000",
width: "500px",
height: "500px",
margin: "20px",
textAlign: "middle"
};
class App extends Component {
constructor() {
super();
this.state = {
currentColor: "blue"
};
}
componentDidMount() {
this.setState({
currentColor: "green"
});
}
changeColor = () => {
this.setState({
currentColor: "red"
});
};
render() {
console.log("in render", this.state);
return (
<div style={parentContainer}>
<button onClick={this.changeColor}>Blue</button>
<p>{this.state.name}</p>
<Child color={this.state.currentColor} />
</div>
);
}
}
export default App;