Where should be the line to separate stateful and stateless component in React? - reactjs

React encourages the use of stateless components as much as possible and have a stateful parent component managing them.
I understand that this can make the stateless components more reusable, and easy to manage.
However, to the extreme, we can always put the state at the top level component, like App.js, and pass down information and callbacks through a long props chain. And if using Flux, the actions can always be dispatched in it too (executed through callbacks).
So I'm wondering what's line to separate stateful and stateless components? And if using Flux, where should the Actions to be dispatched?
--- Add an example ---
Say I have a google docs like web app that have a tool bar and displayed content. I imagine we will have the component structure.
<App>
<Toolbar />
<Content />
</App>
The tool bar has buttons that will affect the display content, say the bold text button.
So should the App pass down onButtonPressed callback props to Toolbar and dispatch Actions in itself, or should let the Toolbar to do it itself?
Should the App pass down contentString props to Content, or let Content itself listen to Store changes?
Thanks!

From my point of view, a simple application could use the pattern of Flux in that way :
Children emit actions.
The application listens to stores and propagates processed data to his children.
With that approach, you have the stateless component, but with a good code organisation without the callback props. But both of your propositions are also correct, it's a decision that you make regarding the size and needs of your application.
If the component that you build will be used outside of your application, don't use flux as much as possible and let the developer choose the wanted approach for his needs.

It's a good question, and it is being solved differently even between different Flux implementations.
I prefer having my state in one high-level component, that sees the "big picrure", and propagate data using props to all the low-level ones. In a good React app, most of the components shouldn't "care" where the data is coming from.
Having a one good structured model instead of several fragmented ones also proves itself to be beneficial so far. (by the way, that can be achieved even using several stores, the high-level component could listen to all of them, and virtually "hold" this big model).
Regarding actions - I prefer having all my "dumb" visualization/ui/display components work with callback props. That way it is easier to re-use them, and it is a good separation of concerns.
In richer components that hold a bit of business logic, I call Reflux actions directly. Usually those are also container components themselves to aforementioned "dumb" ui controllers.
So bottom line - data should flow from as high as possible, actions can be fired from lower components, but always check whether you can achieve the same result with callback props.
To your question - the Toolbar is a complex enough component to have ToolbarActions of its own and call them directly. But the Content component should definitely get its data from above. It's also easier to reason the data flow that way, when the app gets complicated.
Hope that helps. The whole Flux thing is still an art in progress...

Related

React API Data Mutation Best Practice for Component Hierarchy

Let's say I have a hierarchy of React components like this:
ComponentA
ComponentB
ComponentC
...
ComponentZ
My question is fairly straightforward: If ComponentA is responsible for fetching data from a REST API where that data is consumed by ComponentB, ComponentC, and so on, what is the best practice to mutate/update this data via API from a user interaction on ComponentB, or C, etc.? Can this be done in any way that keeps the entire tree of components reusable in a different application or use-case?
Passing in an onChange callback from A down the hierarchy is manageable for small trees of components, but what if the component tree is quite complex?
Should each UI component capable of user interaction have its own API PUT request? Won't this completely eliminate any thought of reusability of these components (particularly if I'd like to reuse components in other locations/apps for different purposes)?
Should I use component composition? Or Context?
This seems like it should be a very common use case, but I am struggling to find any design guidelines for this.
Next JS and SWR help with this by using a global cache of data, and any component down the tree can consume that cached data. However, this quickly becomes tricky when mutating data, especially for re-usable components.
Any thoughts here would be great - apologies for the indirect question here.

What is best practice for handling data in React components?

Currently I have my parent components handling all my Axios calls, and I'll pass that data down with props. Should my child components be handling those requests individually in each child component, what is the best practice?
Should my child components be handling those requests individually in each child component, what is the best practice
There is no such rule which says that parent component should get all necessary data and pass that data down to all child components through props.
We can imagine a situation where we have top panel element which shows:
person name
weather temperature
current date
Yeah, if we make requests from each component, then we will have three API calls. So far so good. But on the next day, client says that he wants to show weather temperature in bottom panel. So we will have weather temperature at the top and bottom panel. It means that we will make 4 API calls. And it is not good solution.
What we can do? So if you are going to need to share the state across a lot of components then we could use state management library or useContext hook (it is simpler and easier to understand than Redux). Both have pros and cons.
If your application is not small, we can use state management libraries such as Redux, MobX, Zustand. However, it is completely okay not to use state management library if your application is not big.
Do You Really Need a React State Management Library?
It depends very much on which and how many components need the data.
Data on which many components depend and do not have to be fetched again and again make the most sense in a parent component.
Data which can be used very limited in a small child component should also be fetched in this component.
The same applies to data that is between these two extremes. A healthy balance prevents components that have nothing to do with the data from being unnecessarily misused as middleman. Furthermore, the parent components render all child components as well. It is therefore all the more important to make sure that the calls happen as selectively as possible.
For data that is needed in each component, I recommend a state manager (React's native reducer and useContext). This prevents prop-drilling, because the data can be easily made available in each component.

If we don't make a React component as Presentation component, isn't this component not easy to be re-used?

I don't quite understand Dan Abramov's 2019 comment in his article Container vs Presentational component.
Is it true that we should still make component Presentational component so that we can re-use them? If we start making components that have an app state, then this component cannot be re-used easily, because then having two of such component on the same page will let them interfere with each other.
So the component can have state, but only "component state", such as whether the comment box is expanded or not, or even the current text in the comment box, etc. It should not be tightly coupled with a certain state in the app. Because then we cannot really re-use this component, unless it is for sure a singleton in the whole app, which mean there is no re-use.
So does it really mean we should write our components so that it is re-usable, and let other component pass in the App data as "props"? This way, we can re-use our components just by passing in different props (and dispatch) from the outer container.
So for our re-usable component, it doesn't matter it is Container or Presentational or combined, just as long as a even higher container can pass it the props and dispatch and let us re-use the component. Is that what Dan really means?
IMHO this statement was more about granularity and separation of biznes logic ... container usually manages some app specific dataset with some set of presentational components.
Of course container component can be reused, too. F.e. list of user followers can use common Apollo client (graphql) as long as our backends are composed using the same (shared) schema (by microservices/federation). It can be freely used in different apps and by using render props we can change its look/behaviour.
It's about reusability in general, it's much easier for stateles (presentational) and locally managed state components (class or functional).

React components with shared state that are far away

I am new to React so please excuse me if this is a noob question but I really could not find the answer in the DOCs or elsewhere.
Let's say I have two buttons with a counter that share the state but are far away from each other in terms of the placement in the UI.
The documentation says the common owner component for both buttons should own the state. It makes sense if the components are next to each other like in the example but what if my buttons are each part of a different UI group and are far away in terms of nesting? My state holder would be the root of the document and I would have to pass a handler function down through many layers. And what if I need to add new component somewhere else that also needs to know the state? Would I have to modify all the parent components in the way to pass the state down? That is tremendously impractical.
Without React I would have some global Subscribe/Publish pattern like jQuery Observer and all UI elements could subscribe/publish to it regardless of their nesting position.
How does React solve this?
Related question: If I need to load/save the state to DB, how do I pass a reference of the controller (or Whatever) to each React component that stores the state?
1 for global state you may use REDUX
Redux is a predictable state container for JavaScript apps
for connect/subscribe component with that state ,you should use react-redux
If components are far away in terms of nesting, you may connect/subscribe them to redux store, and take only neccessary part of state. They will update if only neccessary part is changed.
article that explains how you can do your case
to learn how to use redux you can watch this videos from creator of redux (Dan Abramov)
1.getting-started-with-redux
2.building-react-applications-with-idiomatic-redux
3.I definitely recommend to you discordapp rectiflux channel. because you allways can ask any question online.(there you can find contributors of that tools)
2 alternative way that less verbose then redux is MobX
MobX is a battle tested library that makes state management simple and scalable by transparently applying functional reactive programming (TFRP). The philosophy behind MobX is very simple:
Anything that can be derived from the application state, should be derived. Automatically.
I suggest to look at the Flux stores. In short, stores are like model in your application. You can listen to change (subscribe) and also modify their properties (publish). You can see how it was done in example app.
A better option is to go with Redux.
Redux is enabling use cases like yours in a way simpler fashion :)
It will help you with all the state and make your life much easier.
Some good resources for learning:
The Redux Website
Video courses from Dan Abramov, the creator [Free]
Awesome course on Udemy [Not free]
Building Applications with React and Redux in ES6
And finally take a look at this youtube series [Free]
Managing state in the middle layers of your app should be avoided where possible. This data belongs in a store, which holds the global state of the app. Then each component accesses the state via its props.
The naïve approach to get the data down to the component is to pass the store through all the layers of your app "manually", i.e. through props.
Smarter alternatives exist, which use connected components, that access the global state through the context (as opposed to the props). Typically, the presentational component (your button component) is wrapped in a container component that handles this connection to the store, then passes the data in via props.
There are numerous frameworks that facilitate this process, links to which are already provided in the other answers.
If you are trying to share simple states, try this ( I am the author): react-provide-state
Otherwise I will recommend Redux. It has become the most popular tool for managing application states.
In the applications being working on, we use Redux to manage the main application states and almost all other states. But we use 'react-provide-state' for simple, UI only states like Modal, Checkbox states.

In Redux, should global state replace component state?

My question is, should I still be using stateful React components or should I move that state into the Redux store?
There is no single true answer for you question.
You have different types of states. You have a state of your models (in terms of MVC) and UI (View) state. In classical MVC your models should not depend on UI. So, here we have a question: is it ok to save UI state (inputs, checkboxes state) in global redux store.
The most general rule, in this case, is to use common sense :). You can choose any of the approaches depending on your needs and it will be ok if it suits better for your situation.
But, let's look at several examples.
global redux store for everything
I know apps, that save whole UI state in global redux store. I mean that every keystroke in any field will fire event and will update the global store.
Pros:
It is easy to track state changes when the whole state is in one place.
You can serialize the whole state for debugging purposes. It can be automatic state saving on errors. Or QA engineer can dump UI state with a special keyboard shortcut and send to developers. Developers can take this serialized state and restore whole UI as it was on QA's machine.
Cons:
Rerender the whole app on every keystroke.
A lot of intermediary state (in global store) that is needed only while user entering some data.
Passing state down to your components. You will use "Container" components for this but the question is should your "Container" components be only top-level components or you should wrap leaf dump components in containers. Both variants are acceptable but in most cases it is better to move state higher (while it makes sense). Read about "Smart vs Dumb" components or "Containers vs Presentational components"
You should manage different types of state (from different sources) in one global store.
UI state in your components.
For example, you have a form. And your form manages the state on your inputs by its own. So you just render it as <Form onSubmit={ (fields) => saveFields(fields) }>
Pros:
Intermidate form state is private to form. You can think that this state does not exist at all, it does not matter for you.
The shape of private state is much easier to change.
Components are more coherent. They are more independent, like simple mini applications inside your larger application.
Cons:
Other components cannot access this state.
There is no single place of storing state.
Different appoaches to state management.
Increases possibilty of situations when there will be more than one source of thruth.
Additional resources:
Presentation from ReactConf 2016 about possible options for managing state in ReactJS apps
Dan Abramov's great post about "Container" and "Presentational" components
Great video tutorial from Dan Abramov "Getting started with redux". It shows how to use presentational components and how to manage app state.
Some general ideas that can be useful:
Handle as less state as possible in your components but not less than required. Stateless components are easier to work with. But remeber that the state will be moved somewhere, so you will need to handle it in any case (it can be store, or presentational wrapper component etc).
Make your components as much independent as possible. You can make good independent components with private state or make them stateless.
Split components into presentational components (context independent) and container components (context dependent).
Move state as high as possible. Prefer saving state in upper level components. It can be not only container components. You can create presentational components that wraps you stateless components just to manage state (they will have no connection to redux)
I recommend reading this Medium post: Presentational and Container Components. It outlines the ideas of using component state for UI state but non-UI state is global (redux). It also suggest a pattern of how to approach that by having container components responsible for managing access to the global state and simple view components that the container passes state to as a prop.
So the answer is a little more complicated in my opinion because there are different types of state.
I highly recommend this free video series that goes into Redux in depth and provides a lot of explanation to build your knowledge up quickly: Getting Started with Redux.
After digging into Redux more and using it on a project to learn, I found myself making use of it to store UI state. The particular use case was a long scrolling div. I wanted the scroll position of the div to be the same when the back button was used. It was super easy to hook the click up to a dispatch to update the state for the current div.scrollTop and then on componentMount (back button pressed, component remounts) simply set the div.scrollTop to the position from state.
So I think it can be very useful to have UI state in Redux too. It is easier to reason about and simple to do. I can see building very powerful UIs this way that do not exhibit the typical UI issues seen with single page applications.

Resources