Working with Angular 1.5, and given a component hierarchy such as:
compA
compB
compC
Is there a better way to bubble events from nested child components to the interested parent component?
The two options I see are:
Call $scope.$emit() from compC. Use $scope.$on() in compA.
Pros
compC is decoupled and more likely to be re-usable
compB does not have to be made aware of this output in any way
Cons
Use of $scope, which I was hoping to avoid since it no longer exists in NG2. However, I'm not finding a better solution.
Pass callback from compA to compB and then to compC using a & binding
Pros
compC is decoupled and more likely to be re-usable
Cons
compB has to be involved, making this solution fragile
Maybe I should make an exception and allow $scope use for this scenario. Or, there is the option of emitting/listening on $rootScope instead.
EDIT: I'm finding $rootScope should be used only for truly global events, and it's common to forget to clean up your listeners, which is done automatically on $scope.
One more way of passing data from CompC to CompA (or in between any components) would be to use a service instead of event based message passing. You could define dependency in all the components on a service and use that service to pass data amongs them. This would again make the components reusable.
Related
React Context is a way to make an object available in all components of my React tree without having to thread the object through the props of intermediary components. ES6 modules also offer a simple way to make a singleton global object.
Context is a little more cumbersome because I have to add an element to the render tree for every new thing I want to put in the "global scope". So what's the advantage of using Context over a singleton global object?
The answer I settled with, as alluded to by azium's comment:
Context provides more than just a global variable because it can depend on props or state which might change. On change of the context's dependencies, the context would update and anything that's dependent on the context would rerender.
Actually context does not update your components by itself. Context only updates your components if its using state or some kind of observable.
To answer your question. You could use a singleton with an observer pattern like mobx
I am building SPA with React and have the following structure of UI-components:
App (base layout with navbars and footers)
EventsIndex (Load Events data from API)
FilterBar (common components where current filter settings is shown)
EventsTable (show Events data for desktop)
EventsAccordion (show Events data for mobiles)
SomeOtherIndex...
EventsTable and EventsAccordion have a lot of common logic such as pagination, filter's and sorting's handlers.
I have to lift up handlers from child components(EventsTable and EventsAccordion) to parent EventsIndex. But for me it seems not the best way.
Am i wrong?
What the best practice in such cases?
Should i use Redux? If no, when it better to use it?
React is all about Components, I would say the most important part when starting to design a React App is structuring your Components well.
There are different ways to structure your components well, below are some:
Container Components: When designing your app identify the container components, these are the components which are going to hold state and also manipulate them based on events.
Coming to your question: I have to lift up handlers from child components(EventsTable and EventsAccordion) to parent EventsIndex. But for me, it seems not the best way. Should I use Redux?
Answer: When using container components only a few components are going to deal with the state and any child hierarchy ( Child Components ) are going to be stateless components / ( Functional Components ), so in order to update the state they will have to have handlers passed down by their Container Components, using which these components are going to update state. ( This is absolutely fine, that's the way it should be )
Coming to REDUX, using REDUX in such small scenario is not recommended, I would not recommend it, because it would be an overkill, REDUX is apt in a much complex scenario when you would like to share some state between two component trees, but still you could use REDUX but its just that, its not recommended.
HOC ( Higher Order Components ): Whenever you have some functionality which is reusable, consider creating a HOC
Please check : HOC
Break Components to Smaller Re-useable pieces: This is often very important whenever you see that a component contains code which is used elsewhere, go ahead and make it a Separate Component, thus making it Reusable.
Please check this, this has a bunch of best practices
https://www.toptal.com/react/tips-and-practices
When to use REDUX ?
Basically, you need to be using REDUX, when keeping the state in a top-level root component is no longer sufficient, like for example : ( you have two branches out from root component, one of the child component in branch A wants to access some state in branch B's child, then you need to move it to the root component and again pass it down, such cases are apt for REDUX ).
Please check this source: https://redux.js.org/faq/general#when-should-i-use-redux
You can follow a container type implementation - which means that if there is some common logic between components, they can be encapsulated within a component that acts as a container for these two components and provides the necessary common logic / data.
So, for example in your case it'll be something on the lines of
- EventsIndex (Load Events data from API)
- FilterBar (common components where current filter settings is shown)
- EventContainer (where common logic resides for both your components)
- EventsTable (show Events data for desktop)
- EventsAccordion (show Events data for mobiles)
where EventContainer provides the common props such as pagination, filter's and sorting's handlers.
Hope this helps :)
The best approach that we follow in a team setting (and is opinionated; and probably won't fit in everyone's scenario) is to break the app into logical structures.
- src
- Utils (reusable methods such as sorting, pagination, etc)
- UI (Reusable UI components such as buttons, modals, etc)
- Services (API Calls to the database, further divided by entities /users /posts etc)
- Components (Hierarchy of components)
- EventsIndex (uses the service directory to make API calls)
- EventsIndexContainer (if following container encapsulation pattern)
- EventsTable
- EventsAccordion
If the handler isn't component specific, I'd suggest move it to the utils folder (so that you have a single responsibility pattern as well as a single place to modify your logic rather than in two places) and pass down the handler to the table and accordion from the EventsIndex component or a EventsIndexContainer component that further encapsulates your logical components (the later one is preferred my many who I've worked with).
You are probably wondering what I mean by brothers components, well it's simply 2 different components that have the same parent component.
I am using angular.js 5.11
Let's say I have a parent component with a child1 component and a child2 component. I have a variable vm.active in my child1 component and I wish to use it (in an ng-if if you're wondering) in my child2 view.
Any ideas ? Was thinking of doing two way binding in both 3 components ? What do you all think ? Or maybe considering they are from the same state, probably as a stateParams ? Please let me know if you have any questions
This is the perfect scenario to create a service. Remember controllers have unique instances, but a service passes a common instance around.
https://www.w3schools.com/angular/angular_services.asp
Do not use two-way data binding in this case because you can accomplish the same in a more efficient way. Two way binding setup requires framework overhead.
One approach:
Setup one way binding of the variable (say x) in the Parent component to both of the children.
When child1 makes an update to the variable, pass in an observable reference that the parent can receive. The parent can set the value of x accordingly. Now both the children can see the update.
Here's another:
Use a singleton service. Save the variable in a related service. Use the getters and setter methods to retrieve and update the values.
Well ended up using $scope.$parent.$broadcast in first component and $scope.$on on the second component if anyone is wondering :)
I'm struggling to understand why you'd need to use $emit rather than using the controller as syntax and directly accessing & updating data on the parent scope. What are the use cases?
It's obviously more efficient to call a method on a parent scope directly, rather than using $emit (or $broadcast) to dispatch an event. But there are some valid reasons to do it.
Here's some reasons that come to mind:
You want to emit an event that more than one application component can receive/process.
You want to de-couple your components so that in the future the message may be processed by a different controller (or maybe a service or a directive, etc.).
You want to emit an event that a service/factory can consume (these are not associated with any view/$scope, but you can inject the $rootScope into them).
How do you create a ReactJS component that reaches multiple levels up the component/DOM hierarchy?
A good example of this is a Modal. I want to trigger and control the modal from a child nested way down in my app, but a Modal requires that the DOM be much higher, most likely all the way up as a child of the document body.
I'm considering a "portal" pattern, as described here: https://github.com/ryanflorence/react-training/blob/gh-pages/lessons/05-wrapping-dom-libs.md#portals
FakeRainBrigand even wraps the pattern up nicely in a mixing in this post: https://stackoverflow.com/a/26789089/586181
This feels like a hack to me. Great if you want to use a non-react library like jquery-ui, but without that need breaking out of react just to render a react component somewhere else in the DOM seems like overkill. Is there a more "React" way of achieving this?
Thanks
I'll leave this best to the react documentation. If you must have buried React elements that need to communicate with other elements outside of their Parent Child or possibly even grandparent than see the below.
For communication between two components that don't have a
parent-child relationship, you can set up your own global event
system. Subscribe to events in componentDidMount(), unsubscribe in
componentWillUnmount(), and call setState() when you receive an event.
https://facebook.github.io/react/tips/communicate-between-components.html
I've written a library to help with this. I avoid the DOM insertion hacks used by Portal strategies out there and instead make use of context based registries to pass along components from a source to a target.
My implementation makes use of the standard React render cycles. The components that you teleport/inject/transport don't cause a double render cycle on the target - everything happens synchronously.
The API is also structured in a manner to discourage the use of magic strings in your code to define the source/target. Instead you are required to explicitly create and decorate components that will be used as the target (Injectable) and the source (Injector). As this sort of thing is generally considered quite magical I think explicit Component representation (requiring direct imports and usage) may help alleviate confusion on where a Component is being injected.
You can completely use my library to bind a ModalComponent to a root level component that you decorate with the Injectable helper. I plan on adding an example of this use case soon. It even supports natural props pass throughs, and all the various component types i.e. stateless/class.
See https://github.com/ctrlplusb/react-injectables for more info.