For making a better structure, we have to decide what should go into its own component and what should be a higher order component like the root components we have that wraps other components.
We can make certain changes to our application. Like make a components for the list of foods. Also, we can make a cockpit
component(containing parts of return method of container App.js
).
Now it make sense to have separate folders for components, assets(containing resources like images), and container(higher order components)
Typically, the container components or that manages state, like App.js should not contain much of UI code.
Now our folder structure looks like:
What is a stateful component?
It is a component that manages state. Mainly they are class based components. Now a functional component that manages its own state with the useState would of course also be a stateful component, so stateful does not automatically mean class-based component, though historically this has been the case because React hooks like useState are a really new feature. Still since React 16.8, stateful is not automatically a class-based component. It is a component that manages state, Presentational, also called dumb or stateless components historically have always been functional components because prior to React16.8, these functional components could not manage state.
What is a Stateless or presentational component?
It is a functional component that does not manage state. Even though you could with useState, it is still a good practice to restrict yourself to a couple of components that are involved in the state management and of course, which depends on how big our app is. majority of your components should be presentational, stateless components. Because that keeps your app manageable as we have predictable flow of data.
Its is important to know what kind of properties a component has and what they can do. These differ when it comes to managing state and lifecycle hooks.
Note that 'Lifecycle hooks ' and 'React hooks' aren't the same things.
First thing to note is that this is only available in class-based components. Functional based have something equivalent with React-Hooks.
Here we have certain methods that react will run for us. They run at different points of time and in certain order.
Lets start with methods used while component creation.
First thing we have is constructor(props). It is mainly for basic initialization.
super(props)
if we are using itNext is getDerivedStateFromProps(props,state). It is very rarely use. In some scenario where props of our component can change and then we want to update some internal state if that component, then it will be used.
Next is our render() method. Other child components are rendered after this.
The creation lifecycle ends when componentDidMouunt() is called after.
Now let's try and execute these functions.
In constructor we can initialize our state. Behind the scenes this is actually what happens.
constructor(props){
super(props);
console.log('App.js constructorj');
}
We need to add static keyword here. We should return the updated state here.
static getDerivedStateFromProps(props, state){
console.log('App.js getDerivedStateFromProps', props);
return state;
}
Now the render method executes. After it all the child components will be run. We can see the lifecycle running there too.
render(){
console.log('App.js render');
...
}
Next this method will run
componentDidMount(){
console.log('App.js componentDidMount');
}
We can see the order of execution in inspector window.
Just like there is Lifecycle for component creation there is also for updating.
Now we need convert some of our function-based components to class-based components to use lifecycle methods.
To show the cycle changes made in Foods.js after converting it to class-based component.
static getDerivedStateFromProps(props, state){
console.log("Foods.js getDerivedStateFromProps");
return state;
}
shouldComponentUpdate(nextProps,nextState){
console.log("Foods.js shouldComponentUpdate");
return true;
}
getSnapshotBeforeUpdate(prevProps,prevState){
console.log("Foods.js SnapShotBeforeUpdate");
return null;
}
componentDidUpdate(){
console.log("Foods.js componentDidUpdate");
}
render(){
console.log('Foods.js rendering...');
...
}
Inspector window :
const cockpit = (props) => {
useEffect(()=>{
console.log('Cockpit.js useEffect');
})
...
}
Whenever the app is re-rendered this method is called.
Inspector window:
The method is running a lot of times. Let we want to send a HTTP request only when component first renders. To mimic this behaviour we use setTimeout()
. And there is a shortcut to only run it on first render using an empty array as second argument of useEffect. In this array we basically tell the dependencies of the method. When empty the dependencies don't change hence it only runs once.