I am fooling around while learning React and I would like to know what would be an elegant solution for the scenario presented below.
Follow this Link to see the complete code set.
I have a child
component, that has a <h1>
tag
. This tag returns a message that I am displaying dynamically as will be shown below.
App root container
I have my state
on this container
, and I want to keep it just there.
State:
The object of discussion here is the cockpitAlert
object
.
state = {
state = {
persons: [
{ id: "a", name: "foo1" },
{ id: "b", name: "foo2" },
{ id: "c", name: "foo3" }
],
CockpitAlert: {
regular: "Some message",
alert1: "The array is ending",
alert2: "There is nothing to show"
}
};
Below is how I delete the rendered items - still on App.js
personDeleteHandler = index => {
const person = [...this.state.persons];
person.splice(index, 1);
this.setState({ persons: person });
};
Below is where I render my JSX
render() {
return (
<div className="App">
<Cockpit
regular={this.state.CockpitAlert.regular}
alert1={this.state.CockpitAlert.alert1}
alert2={this.state.CockpitAlert.alert2}
personsLength={this.state.persons.length}
/>
<Person click={this.personDeleteHandler} persons={this.state.persons} />
</div>
);
}
Cockpit child
Below is the logic. let message
dynamically changes the props
according to the length of the persons
array
, that gets shortened upon clicks.
import React from "react";
function Cockpit(props) {
let message = props.regular;
if (props.personsLength <= 2) {
message = props.alert1;
}
if (props.personsLength === 0) {
message = props.alert2;
}
return (
<div>
<h1>{message}</h1>
</div>
);
}
export default Cockpit;
As you can see this does not look very nice at all.
I don't want to have all of these different props
being pointed on my logic:
regular={this.state.CockpitAlert.regular}
alert1={this.state.CockpitAlert.alert1}
alert2={this.state.CockpitAlert.alert2}
personsLength={this.state.persons.length}
I wonder if there is a way that I could pass just one props
, e.g props.message
and change it dynamically, probably through setState()
on the root
level, where the state
is set without having to move my logic from Cockpit
to App.js
Well I have discovered how to solve this issue using React Context API
here is the updated CodeSandBox
I have first created the file auth-context.js
in order to pass my state from the Parent
component to the child
component.
As the logic is already based on the Cockpit.js
I will only pass my state
through React Context ApI
in this case.
auth-context.js
file
import React from 'react'
const authContext = React.createContext({
persons: [
{ id: "a", name: "foo1" },
{ id: "b", name: "foo2" },
{ id: "c", name: "foo3" }
],
message: "Some message",
});
export default authContext
On my App.js container
Now I have set the Provider
in the App.js
root
container:
//first of all, import the file into the root element which will Provide the //initial state on this API
import AuthContext from "./Context/auth-context";
...
class App extends Component {
state = {
persons: [
{ id: "a", name: "foo1" },
{ id: "b", name: "foo2" },
{ id: "c", name: "foo3" }
],
CockpitAlert: {
message: "Some message"
}
};
personDeleteHandler = index => {
const person = [...this.state.persons];
person.splice(index, 1);
this.setState({ persons: person });
};
render() {
return (
<div className="App">
//I am wrapping the whole deal here and set my state so I can manage it at
// the Cockpit.js file further on
<AuthContext.Provider
value={{
persons: this.state.persons,
message: this.state.CockpitAlert.message
}}
>
//no more props being passed at Cockpit.js!!!
<Cockpit />
<Person
click={this.personDeleteHandler}
persons={this.state.persons}
/>
</AuthContext.Provider>
</div>
);
}
}
export default App;
Now I will pass my state
into the child component
Cockpit.js
file
import React, { useContext } from "react";
//must import AuthContent here as well.
import AuthContext from "../../Context/auth-context";
function Cockpit(props) {
//this is the way of setting it up on a functional component
// now I have access to the state through authContext
const authContext = useContext(AuthContext);
//here I will point my state into different messages
if (authContext.persons.length <= 2) {
authContext.message = "running out";
}
if (authContext.persons.length === 0) {
authContext.message = "nothing else to render";
}
//as you can see there are no props created
return <div>{<h1>{authContext.message}</h1>}</div>;
}
export default Cockpit;
Now my reflection is:
This is not mutating the original state, at App.js
. Would this be a good practice in this case?
What do you guys think?