React: How to pass data and methods to hierarchically organized components - reactjs

i have a page with components distributed by layers as follow:
I have a main page that contains several components and which in turn contains other components. Each level of the parent-child hierarchy I call a layer.
I separate these components into 3 types, reusable, coupled and modal:
Reusable - Receive data by props and do what they need to. They can be reused in any context (page) because they are not coupled.
Coupled - They are bound to the context (page) and can receive data by props or fetch data via API request.
Modal - It is the last layer of the layers, however they are decoupled and receive the data and methods of the actions they need to perform.
The flow I run today is to get the main data when entering the page, then I pass the data via props to the respective components, as the user accesses it.
In some cases, due to the amount or sensitivity of the data, I request more data inside the coupled component, when the client accesses a higher level of detail.
And finally, I pass the data and methods to be executed in the last layer (modal components). There are scenarios where the method is created on the 1st layer (page) and only executed on the last layer (modal).
Based on this context above, what would be the most efficient way to pass data and methods to components?
Currently I pass via props, however, I still have doubts if this would be the best way or using ContextAPI.

I agree with you #kanuos !
After many time thinking about it, I'm using 3 options.
But which one do I choose? As #kanuos sad, depends!!
These are the 3 options I have and use:
Continue using Props Drilling - Some cases is necessary.
Use Context - It works well to avoid a lot of prop drilling.
Composition - Sometimes I want to avoid a lot of prop drilling and I also don't want to maintain a context dependency. In this case using the composition pattern I can directly pass the
properties to what I want.

Related

React- Apollo Client- structuring components

Let's say component - TodoList need to show the list of TODO's in 2 different ways, listview and gridview .there is a switch on the page that toggles between the views. Assuming I want to keep the 2 views as different components, what is the best practice -
create TodoList component with graphql query and then pass the result of the query to TODOListView and TODOGridView components?
create TodoList component with NO graphql query and then write the same grqphql query inTODOListView and TODOGridView components (not DRY, query duplication in each component, but apollo cache will make sure that it is not called multiple times)?
good/bad with each approach?
IMHO there is no real choice, cache usage has no value as argument then no good parts with second approach.
Taking usability, UX, user centric design you probably want to keep page, sorting and filtering state while switching type of view. As an user you're expecting this kind of behaviour. This is easily available only with first solution.
Assuming I want to keep the 2 views as different components
IMHO this is wrong assumption, too. Of course you can do that but Lists are almost the same, the real difference is in item/row rendering. If this is a simple styling sets change (or adding a few elements) then even no need for using components for items, just conditional rendering. You can change/refactor it later.
Utilizing item components you can have additional abstraction layer and more complex use cases available. With passed down (into items) switching type handler I was able to change it (gloablly) from simgle item level or change locally item view type - mixed element list.

How complex should a presentational component be before making it smart?

As I see it, I could make my entire app a presentational/dumb component and then have a single container component pass the appropriate props.
On the other extreme, I could make every single component smart.
So, is there a rule of thumb to decide when to make your presentational component smart?
Quoting from Presentational and Container Components by Dan Abramov:
When to Introduce Containers?
I suggest you to start building your app with just presentational components first. Eventually you’ll realize that you are passing too many props down the intermediate components. When you notice that some components don’t use the props they receive but merely forward them down and you have to rewire all those intermediate components any time the children need more data, it’s a good time to introduce some container components. This way you can get the data and the behavior props to the leaf components without burdening the unrelated components in the middle of the tree.
... This is an ongoing process of refactoring so don’t try to get it right the first time.
I would argue that there should be a nice balance between the size/complexity of the app and the number of smart components (containers).
Consider introducing a container when:
The hierarchy becomes too deep and passing props around becomes a hassle.
It is likely that an entire feature (UI + data mapping) will be moved/re-used across the app.
There's a need to encapsulate a feature for reasons such as the above or any other (versioning, security, lazy-loading etc.)
You identify unnecessary updates as a result of data mapping.
On the other hand, consider sharing a container when:
Multiple components use data of the same nature and form a single unit that might be considered a "feature".
Mapping (mapStateToProps/mapDispatchToProps) becomes repetitive amongst multiple proximate components.
Also, keep in mind that refactoring might be necessary as your app evolves.

How to structure Redux for a highly de-coupled, plug-n-play complex component?

I'm pretty new to Redux and would like to use it my application but I'm stuck at architecture/design phase for the Redux part. Here are my requirements and my suppositions regarding the design.
Application details:
SPA with AngularJS. Other libs used ng-redux, reselect, rxjs.
Component details:
Re-usable grid component to render huge amounts of data.
My idea:
Create a plug-n-play kind of component-based architecture, where all the internal components of the grid are independent of the parent/composing component like search, sort, row, header, cell.
All the components will have their own set of reducer, action, selector, and slice of state from the store.
Because all the components have their own reducers and can be plugged-in on demand, I need them to be lazily registered to the store instead of being accumulated in one place.
Some of the components like search, sort along with having their own state, also can affect other components state. Ex: setting up of query parameters (searchText, sortOrder etc.) to fetch the grid data which would be handled by another component(s).
My thoughts:
For the 1st point, I'm looking into reselect for supplying the dependent slice of state.
For the 2nd point, I'm still confused about which to use combineReducers/replaceReducer for the lazy registration. I feel combineReducers will not fit if I want access to multiple parts of the state.
For the 3rd point, I'm thinking of following approaches:
a. Passing entire state via getState() wherever required to update multiple parts of the state. Though this approach gives me feeling of improper use of Redux.
b. Component A fires its own action which updates their part of the state, then another action is fired for the other component B to update its slice of state. This approach as well feels like breaking the whole idea of Redux, the concept of side-effect could be used here though I don't know how to use it, maybe redux-saga, redux-thunk etc.
NOTE: Use of either of the approaches shouldn't lead to the component knowing about the other components hence whatever has to be done will be done by passing a generic config object like { actionsToFire: ['UPDATE_B'] }.
I need state management while navigating back and forth between the pages of the application, but I don't require hot-reloading, action-replay, or pre-fetching application state from server-side.
Components will also be responsible to destroy their state when no longer required. And state will have a normalized structure.
I know the requirements might seem weird or not-seen-often but I would keep them that way.
Few things I already know are:
I don't need to use Redux like the classic article from Dan says, but I think I need it here in this case.
I know about the Smart and Dumb components, mostly my components might seem smart (i.e aware of application state) but that is how I want to keep them, I might be wrong.
Diagram of the grid component:
Grid Component Diagram
Redux's global store makes encapsulation and dynamic plug-and-play behavior more difficult, but it is possible. There's actually many existing libraries for per-component-instance state and dynamic registration of reducers. (That said, the libraries I've seen thus far for component management are React libraries - you'd have to study some of those and reimplement things yourself for use with Angular.)

Correct way to update owner state

I have two components, contact form, and input.
At this moment i pass onChangeEvent from contact to input as is described in many tutorials and its works fine - input update his owner state.
But there is way to pass 'this' from contact to input by prop, or context and then I can update owner state without passing onChangeEvent - but is this a good idea?
Is there another option to update owner state without passing onChangeEvent?
I believe you could technically do it, as a React component is a regular javascript object in the end, so you could pass it as a prop.
However, that's not a good idea in general, for various reasons:
It tightly couples the two components together. If you ever want to reuse the input component in another place, you'll need to pass in the exact same state.
Linked to this, it allows manipulation of the internal state of one component, by another component, which is a violation of good OO design.
You are right however, that things tend to become quite verbose when working like this. They also become hard to reason about when one has more complex trees of components passing props and change handlers between them.
One solution to the problem, is employing the Flux design pattern, and namely it's Redux implementation.
In Redux one has a single piece of global state, a plain object, of which components see pieces (sub objects). Components receive this state as props, and just render from it in a simple fashion. There's a set of actions which transform this state, and any component can issue such an action, as a result of user interaction. There's still the concept of "state", but it is reserved for truly local things, such as the state of a form before pressing the save button etc.

React/Flux efficiency: how to prevent an action from triggering multiple renders of a component?

I'm still studying the Flux architecture, and noticed that:
one Action can cause multiple Stores to emit a "change" event
one ControllerView can be subscribed to the "change" event of multiple Stores
So, if ControllerView depends on data of two Stores, and those two Stores are both changed by one Action, the ContollerView - with all its components - will be rendered (to the virtual DOM) twice, the first time with incomplete data.
Is there any recognized pattern to avoid this? I can think of some simple solutions, but I wouldn't like to reinvent the wheel.
In general, you should just allow it to render more than once. However, the if the action always triggers actions in both stores you can use the "waitFor()" method of the dispatcher to let one store update first, then only emit a change when the second store gets updated.
This is only useful if the action will always affect both stores, however.
Best practice in flux pattern is to limit number of stateful components, and try only to have top component listen to stores, and send down all relevant info in props.
With multiple stores, one solution to minimize multiple renders after a single change:
create a StatStore that stores nothing, but listens to all relevant Actions, and waits for all other relevant stores.
this StatStore has getter functions, that collect (and possibly calculates stats) from other stores
your top component only listens to StatStore change emissions
top component then gets data from StatStore.
That way, a single change only results in one re-render.
I'll add this for future reference: I didn't find any good solution to this problem with vanilla Flux, and in the end switched to Redux, which has all the advantages of Flux and doesn't suffer from this disadvantage.

Resources