We are starting to work on a project as 3 students who are new to react. I wanted to split the code so everyone could work on something at once. But when I tried to use a state from icon-bar.js in App.js I got error messages. App.js
import React, {Component} from 'react';
import './App.css';
import IconBar from './ponents/icon-bar';
import Events from './ponents/events';
function App() {
return (
<div className="App">
<h1 className="Title">ENAKS</h1>
<IconBar />
<Events />
<div className="mainModeFrame"><p1>{this.state.mode}</p1></div>
</div>
);
}
export default App;
icon-bar.js
import React, {Component} from 'react';
import '../App.css';
class IconBar extends Component {
constructor() {
super()
this.state = {
mode: 'Hi'
}
}
render() {
return(
<div className="icon-bar">
<div className="iconHolder">
<img src="/images/2dlogo.png" alt="" className="icons" onClick={() => this.setState({mode: '2d'})}/>
<img src="/images/3dlogo.png" alt="" className="icons" onClick={() => this.setState({mode: '3d'})}/>
<img src="/images/flag.png" alt="" className="icons" onClick={() => this.setState({mode: 'edit'})}/>
<img src="/images/tracker.png" alt="" className="icons" onClick={() => this.setState({mode: 'track'})}/>
<div>{this.state.mode}</div>
</div>
</div>
)
}
}
export default IconBar;
How can I use my "mode" state to change my p1 in the App.js
We are starting to work on a project as 3 students who are new to react. I wanted to split the code so everyone could work on something at once. But when I tried to use a state from icon-bar.js in App.js I got error messages. App.js
import React, {Component} from 'react';
import './App.css';
import IconBar from './ponents/icon-bar';
import Events from './ponents/events';
function App() {
return (
<div className="App">
<h1 className="Title">ENAKS</h1>
<IconBar />
<Events />
<div className="mainModeFrame"><p1>{this.state.mode}</p1></div>
</div>
);
}
export default App;
icon-bar.js
import React, {Component} from 'react';
import '../App.css';
class IconBar extends Component {
constructor() {
super()
this.state = {
mode: 'Hi'
}
}
render() {
return(
<div className="icon-bar">
<div className="iconHolder">
<img src="/images/2dlogo.png" alt="" className="icons" onClick={() => this.setState({mode: '2d'})}/>
<img src="/images/3dlogo.png" alt="" className="icons" onClick={() => this.setState({mode: '3d'})}/>
<img src="/images/flag.png" alt="" className="icons" onClick={() => this.setState({mode: 'edit'})}/>
<img src="/images/tracker.png" alt="" className="icons" onClick={() => this.setState({mode: 'track'})}/>
<div>{this.state.mode}</div>
</div>
</div>
)
}
}
export default IconBar;
How can I use my "mode" state to change my p1 in the App.js
Share Improve this question asked May 9, 2020 at 22:57 taylan.unvertaylan.unver 331 gold badge1 silver badge3 bronze badges 3- check out redux. – Alwaysblue Commented May 9, 2020 at 22:58
- @CiBoz I was drafting my answer. Answered below. – Alwaysblue Commented May 9, 2020 at 23:05
-
put mode in parent p state and pass as prop in render
<IconBar mood={this.state.mood} />
and access in child p withthis.props.mood
– Brian Patterson Commented May 9, 2020 at 23:26
2 Answers
Reset to default 3Finding the correct ponent to hold your state is important. Here you want to move your mode to the parent ponent state and access it from child ponent as a prop.
I see your child ponent is setting mode which is a little tricky since it will now be held in the parent state, so how to do that ?
You create a callback in the parent and set that callback as a prop when you call your ponent in the parent render.
You will then need to set your onClick event handler on each image element to call an event handler (in this case handleClick) in your child ponent.
This event handler will then grab the id of the target element and pass that to the parent using this.props.onUpdateMode (the callback that we passed as a prop).
The parent callback receives the data from the child, and updates state accordingly.
Reference: Lifting State Up
import React, {Component} from 'react';
import './App.css';
import IconBar from './ponents/icon-bar';
import Events from './ponents/events';
class App() extends Component {
constructor(props) {
super(props)
this.state = {
mode: null
}
this.updateMode = this.updateMode.bind(this);
}
updateMode = (newMode) => {
this.setState({mode: newMode});
}
return (
<div className="App">
<h1 className="Title">ENAKS</h1>
<IconBar onUpdateMode={this.updateMode} mode={this.state.mode} />
<Events />
<div className="mainModeFrame"><p1>{this.state.mode}</p1></div>
</div>
);
}
export default App;
import React, {Component} from 'react';
import '../App.css';
class IconBar extends Component {
constructor(props) {
super(props)
this.handleClick=this.handleClick.bind(this);
}
handleClick(e) {
let mode = e.target.id;
this.props.onUpdateMode(mode);
}
render() {
return(
<div className="icon-bar">
<div className="iconHolder">
<img src="/images/2dlogo.png" id="2d" alt="" className="icons" onClick={this.handleClick} />
<img src="/images/3dlogo.png" id="3d" alt="" className="icons" onClick={this.handleClick}/>
<img src="/images/flag.png" id="edit" alt="" className="icons" onClick={this.handleClick}/>
<img src="/images/tracker.png" id="track" alt="" className="icons" onClick={this.handleClick}/>
<div>{this.props.mode}</div>
</div>
</div>
)
}
}
export default IconBar;
There are two ways to do this.
The first one is to use something like redux. where you have global store for the state which can be shared across different ponents.
The second one would be to emit the state in the parent ponent. Here Icon bar should be child ponent to your parent ponent app.js
. From parent ponent you pass function as a props and that function should take an argument which could be state
Below Icon bar takes props now (see constructor and super)
import React, {Component} from 'react';
import '../App.css';
class IconBar extends Component {
constructor(props) { //
super(props)
this.state = {
mode: 'Hi'
}
}
render() {
return(
<div className="icon-bar">
<div className="iconHolder">
<img src="/images/2dlogo.png" alt="" className="icons" onClick={() => this.setState({mode: '2d'})}/>
<img src="/images/3dlogo.png" alt="" className="icons" onClick={() => this.setState({mode: '3d'})}/>
<img src="/images/flag.png" alt="" className="icons" onClick={() => this.setState({mode: 'edit'})}/>
<img src="/images/tracker.png" alt="" className="icons" onClick={() => this.setState({mode: 'track'})}/>
<div>{this.state.mode}</div>
</div>
</div>
)
}
}
export default IconBar;
and then in app.js
import React, {Component} from 'react';
import './App.css';
import IconBar from './ponents/icon-bar';
import Events from './ponents/events';
function App() {
const getStateFromChild = state => {
// body of function
// return something
}
return (
<div className="App">
<h1 className="Title">ENAKS</h1>
<IconBar upsideEmit={getStateFromChild} />
<Events />
<div className="mainModeFrame"><p1>{this.state.mode}</p1></div>
</div>
);
}
export default App;
When do you want the state to be sent to the parent ponent depends on you.
[Update:] I do something very similar in one of my open source repo. instead of navigating through the entire code, look at this line
Here I have a parent ponent, In which I have child ponent Checkboxes
<CheckBoxes
options={options}
upsideEmit={onChangeHandler}
defaultColor={defaultColor}
/>
CheckBoxes is passed a function onChangeHandler upsideEmit={onChangeHandler}
(ignore the body of the function)
const onChangeHandler = (data, errorMessage=null) => {
// Error Message is usually passed from the child ponents (look ad date ponenet example )
if (!errorMessage && (data === '' || data)) { // Doing data = "" in case someone want to remove last char of a string
const currentData = {...payload}
currentData[key] = data
setPayloadData(currentData)
} else if (errorMessage) {
setErrorData({status: true, message: errorMessage})
}
return
}
Now, If you look at this line in checkboxes ponent, I am passing my child state to parent ponent
const toggleState = (index) => {
let copyState = [...state]
const previousState = copyState[index]['value']
if (multipleSelect) {
// Setting all other values as false, since the array for checkbox won't in normal scenario be big, we can just iterate and set it to false
copyState = copyState.map(element => {
element.value = false
return element
})
}
copyState[index]['value'] = !previousState
setState(copyState)
upsideEmit(copyState)
}
If this helps, please give the repo a star.