I guess, this issue has been discussed before, both for the new RC router and the deprecated router. The favored solution seemed to be using services for passing data down to components activated by router-outlet.
However, the more I think about it, the more I find myself in a hell of concurreny, observables and eventemitters. Please consider the following scenario:
A route is called like this: "/car/123/motor/4/sparkcoil"
which means: get the data for the spark coil for the motor with ID 4, which, in turn, is part of a car with ID 123.
So, there are 3 components with nested routes, the "car" component, the "motor" component and the "spark coil" component. The first components have a router-outlet, in which the child component is rendered. Not too difficult, so far.
Let's make some assumptions:
1)
In the "motor" component I need access to to the car data, and in the "spark coil" component, I need to have access to both the car data and the motor data.
2) The backend call to get a car would not contain data about all of the available motor types, because of the immense data volume. So car, motor and spark coil data have to be fetched in separate backend calls.
The first component that is activated is for the route "/car/123" is the car component. It has a service injected, that makes the backend call and returns an Observable, to which the components subscribes.
Then, the second route "/motor/4" is activated. I need to know about the car object fetched by the parent component. Later on, the "/sparkcoil" component is activated, which needs to know about the motor and the car, as well. Obviously there is not way to get it passed by an #Input decorator, right now. Frequent recommendations are: use a service. Alright, so I inject service X into both the car and the motor component. Here comes the pain. I have no satisfying solution for designing the service without finding myself in a concurrent hell of eventemitters or observables.
Idea 1:
The car and the motor component call a function on the service named fetchMotor(id) and fetchCar(id) which, in turn, trigger the next() method of a motorFetchedEventEmitter and carFetchedEventEmitter. The motor and the sparkcoil component subscribe to all of the EventEmitters to get informed about when the backend data have been fetched. However, I don't know if the components subscribe to the EventEmitter before or after they fire. If before, everything is fine, if after, I need to need to "replay" the emittals (see Observable.replay(...)). Since the service and their EventEmitters are instantiated only once, replaying the Observables means that I may get a lot of (irrelevant) events.
Idea 2:
I'll do it the other way round. The car and the motor component remain idle until the spark coil component is called. This component resolves all route segments, performs the respective backend calls and propagates the backend response via EventEmitters of a service to the "car" and "motor" component. I admit that this approach is quite counterproductive in regards to the new component routing as of RC1.
Possibly there is a better solution for this scenario, considering life cycle hooks. According to the docs, the OnActivate interface (see https://angular.io/docs/js/latest/api/router/OnActivate-interface.html)
says, that when onActivate returns a promise, all child components won't be activated until the promise resolves. I don't think that there is a similar functionality for routed components.
Does anyone have a notion how to solve this as elegantly as possible.
Thanks for your ideas in advance. I need to get a coffee! :-?
You shouldn't use EventEmitter in services. This was common practice for quite some time but EventEmitter should only be used for #Output() on components.
I think the whole problem is just a design problem about how you use observables and services (I don't say its an easy problem to solve).
Using BehaviorService might be an option to fix timing issues where services subscribe to observables after these emitted a value. With BehaviorService a new subscriber immediately gets the last emitted value passed.
Your question doesn't contain enough information for more detailed suggestions and seems a bit too broad for StackOverflow anyway. If you can break down your problem to single issues and create new questions for these it might be easier to make concrete suggestions about how to fix it.
Related
It seems to me the trend is replacing Redux with React Context API and useReducer.
I personally do not like a huge store at root with states from user data to if a dialog is opened all mixed together.
Switching to React Context API allowed me to push the state down and closer to where they will be used. However I can only push it down to the level that child components are either displaying or modifying that value. For example:
<Parent>
<CounterDisplay/>
<CounterIncreaseButton/>
</Parent>
I have to have count on Parent and create a Context. Within the Context, I'll add the count value and an increaseCount method (or a state and a dispatch function when use reducer pattern). Then I provide the context to those 2 child components. Now one can display it and one can modify it.
Now what if I need another button located far from this part of the component tree that also need to change the count value? I have to lift the state up and maybe all the way to the root. That feels strange to me.
2nd issue is when states are scattered at multiple level along the path in the tree, when something happens say user click a button, you may need to call multiple functions from multiple contexts (or dispatch multiple actions, one for each state that may or may not change). Unlike when use Redux since everything is at the root, you just need to dispatch one action.
So what if instead I have an event pub/sub at the root level? I can have the counter state and code manipulate it pushed down even more to CounterDisplay. CounterDisplay need to subscribe to the pub/sub system and listen to the event and update counter correspondingly. And whichever component want to change the counter can just raise an event.
What am I missing in this pattern? Circular event loop? Raise conditions? Feels a good pub/sub library can prevent these. I looked around and did not find something existing. I looked at RxJS but don't feel that fits.
Thanks in advance for sharing your thoughts.
You've basically just described the exact reason for Redux to exist :)
Redux is "an event pub/sub at the root level", and can specifically be beneficial in cases where widely separated components need to make use of the same data.
You may want to read my post Redux - Not Dead Yet!, which describes how Redux fits into today's ecosystem (including comparisons vs context) and some of the reasons you might find it useful.
If you are put off redux by the amount of boilerplate.
I would suggest taking a look at redux-zero.
Under the hood. react-redux uses a context provider at the root.
When you use the connect Higher-Order-Component that is using the context.
Same with the redux hooks.
So it's quite normal to have the provider at the very top.
It would be the same for any library like the react-router to do the same.
I would suggest you keep trying without redux so you can learn more. Put the provider at the root. It won't impact performance in anyway.
Isolate the context you create and the provider to a singleton file and import it to the components you need
How can I pass asynchronous data from a parent controller to a child component? I am using angular 1.5.0 in order to create a child component that I would like to reuse in other views/controllers. I want to make the server calls in a parent controller/component and use the returned data in the child component, maybe modify it using a function. If I want my component to be truly reusable, then I don't want to have to put any code into my parent controller to direct the data.
In theory, I should be able to instantiate the component in the parent controller view, pass in the asynchronous data, and be able to use it in a function in the component when the data is returned.
I encountered this exact same problem with Angular 2. Am I not supposed to pass asynchronous data to components? If I want to do something with asynchronous data, do I always have to call for it in the component? This seems to be a huge flaw if someone needs to view the data in multiple ways and wants to use it in multiple components... This has been bugging me for days, and years if you count the Angular 2 issues. Any explanation or reasoning would be appreciated. Thank you in advance.
Here is an article which instructs to embed a component within a component so that you can start watching a binding. It is a very round about way of doing things, but it seems to do the job. It just seems ludicrous this functionality was not already anticipated when they created components, most data used in general is asynchronous, and it would be nice to have components that only deal with taking in the data, massaging it, and displaying it; without having to make it's own service calls. What if you have a few components that display the same data and you wish to embed them all in a controller's view that does the work of getting and updating the data and then passing it to those components? This seems like a likely scenario, and one I often encounter. So here is the article:
https://www.bersling.com/2016/09/10/wait-for-the-bindings-of-a-directive-in-angular/
It functions even though the code is not as pretty as wished, and I don't know the repercussions of this particular implementation, but it works. If I am overlooking an unforeseen issue, or if there is a better way, I am open to suggestions. Thank you.
I'm new to React and trying to get how to build a good app architecture with it.
I also use typescript with all that features: interfaces, async-await, generics, etc. So, I'm puzzled about implementing some patterns:
1) Dependency Injection and reusable component instances
The first thing I can't get through is DI. Let's say we got a component class UserProfile that requires some dependencies like UserProvider. It would be perfect if the component instance (with deps injected) could be reusable, but I'm afraid it's only my dreams, not the react guys'. :)
So, I'm supposed to place this component this way:
<UserProfile id={123} />
Ok, what's the proper way to inject the dependency here? As an attribute like this <UserProfile id={123} dependency={userProvider: userProviderInstance} />?
Don't you think it is weird to put component input data, options/parameters and dependencies all together? I'd be happy if I could clearly separate them and put generic restrictions on the component class. What's the best practice?
Another side of impossibility to reuse component instances is the fact we must carry some needless objects through all the components structure just to inject them somewhere deep at the bottom. And nobody tells you what component does really use them. And try to imagine what adding a dependency to a low-level component will take in a large project. I just can't.
2) Using Promises
Let's consider a simple component that is supposed to render a counter: <Counter value={123} />.
Now, value is got from some API by calling a method getCounter(id: number): Promise<number>;, so the obvious way to put all together could look like this:
<Counter value={await provider.getCounter(id)} />
But i't impossible, I know. The common practice tells us to make it through setState method and rerender the component after the value is received.
Now imagine that the parent component is pretty complex and has many different providers. So, the parent component may not have definite state typing. It also may be conditional, you know...
You could suggest me implement the async getting in the Counter component, but i will refuse for a simple reason: That component does not know anything about the value's origin. In other cases the value is passed directly as a number. So, do you got better ideas how to keep code clean and simple while using promises?
Please, let me know if you come across some good articles or have your own experience in solving these issues.
PS: Thanks for attention! :)
This topic is a subject of bias - so below I will give my very personal thoughts on the topic that does not pretend to be absolute truth.
DI.
This is indeed not so common pattern in react as it is in angular. But having both context and properties in components allows you to archive the same level of separation as with pure DI. Check the context - it will help you to get rid of passing same props through the whole component tree. There are quite a few articles on this topic already (one, two) - check them out. Also you might be interested in reading this thread).
Promises
I do not really see any problem here. React has a simple concept - basically you have state and based on this state your app can render itself. Whereas rendering is not async operation - the preparation/update of the state can easily be done asynchronously and after results are assigned to the corresponding parts of the state - the necessary child components will be updated automatically. If you component has no knowledge of how to obtain value - it should not try to do it in first place - value should be passed down as props.
Most of the Flux documentation I've found is lacking in the discussion of Components vs. Containers.
I know that it's considered best practice to have containers as the sole elements responsible for listening to the stores. This absolutely makes sense because;
It limits the number of components listening to the stores.
Child components have a single place (their props) to receive data from.
But some explanations imply that Containers should also be responsible for all calls to the ActionCreator. And on that point, I'm not really seeing the advantages.
Convince me I'm wrong?
Disclaimer: My only experience with Flux comes from Redux, which isn't quite the same pattern - that said, I believe the concept is the same either way.
Effectively, the reasoning behind having the container call the action creators is the same as the reasoning for passing data through the props instead of just having every component listening to the store - it means that your presentational components don't need to know anything about the world around them.
Take the (completely original and not overdone in the slightest) example of a Todo list app. You could hard-code that clicking a TodoItem fires a CompleteTodo action - but then if I want to display a read-only version of the item elsewhere in my app, I'd have to make another version of the component that doesn't call that action creator. If you pass a callback that calls the action creator in as an optional prop instead, the item no longer has to manage what happens when it's clicked - it just has to tell the parent when it happens, then the parent is free to do what it wants with that information, or even ignore it entirely.
It's not a perfect example, but hopefully it illustrates the reason why some people recommend doing it that way!
An application that I develop was initially built with Flux.
However, over time the application became harder to maintain. There was a very large number of actions. And usually one action is only listened to in one place (store).
Actions make it possible to not write all event handler code in one place. So instead of this:
store.handleMyAction('ha')
another.handleMyAction('ha')
yetAnotherStore.handleMyAction('ha')
I can write:
actions.myAction('ha')
But I never use actions that way. I am almost sure, that this isn't an issue of my application.
Every time I call an action, I could have just called store.onSmthHappen instead of action.smthHappen.
Of course there are exceptions, when one action is processed in several places. But when that happens it feels like something went wrong.
How about if instead of calling actions I call methods directly from the store? Will my application not be so flexible? No! Occurs just rename (with rare exceptions). But at what cost! It becomes much harder to understand what is happening in the application with all these actions. Each time, when tracking the processing of complex action, I have to find in stores where they are processed. Then in these Stores I should find the logic that calls another action. Etcetera.
Now I come to my solution:
There are controllers that calls methods from stores directly. All logic to how handle action is in the Store. Also Stores calls to WebAPI (as usually one store relating to one WebAPI). If the event should be processed in several Stores (usually sequentially), then the controller handles this by orchestrating promises returned from stores. Some of sequentials (common used) in private methods of itself. And method of controllers can use them as simple part of handling. So I will never be duplicating code.
Controller methods do not return anything (one-way flow).
In fact the controller does not contain the logic of how to process the data. It's only points where, and in what sequence.
You can see almost the complete picture of the data processing in the Store. There is no logic in stores about how to interact with another stores (with flux it's like a many-to-many relation but just through actions). Now the store is a highly cohesive module that is responsible only for the logic of domain model (collection).
The main (in my opinion) advantages of flux are still here.
As a result, there are Stores, which are the only true source of the data. Components can subscribe to the Stores. And the components calls the same methods as before, but instead of actions uses controller. Interaction with React did not change at all.
Also, event processing becomes much obvious. Now I can just look at the handler in the controller and all becomes clear, and it's much easier to debug.
The question is:
Why were actions created in flux? And what are their advantages that I have missed?
Actions where implemented to capture a certain interaction on the view or from the server which can then be dispatched to as many different stores as you like. The developers explained this with the example of the facebookchat.
There is a messageStore and a threadstore. When the action eg. messagePost was emitted it got dispatched into both stores doing different work to update their attributes. Threadstore increased the number of unread messages and messageStore added the new message to its messagearray.
So its basicly channeling one action to perform datachanges in more than one store.
I had the same questions and thought process as you, and now I started using Flummox which makes it cleaner to have the Flux architecture.
I define my Actions in the same file where I define my Store, and that's close enough. I can still subscribe to the dispatcher to log events so I can see all actions being called, and I have the option to create multi-store Actions if needed.
It comes with a nice FluxComponent that lets you wrap all store-related code in a single place so its children are stateless components that get updated on store changes, like
<FluxComponent connectToStores={['storeA', 'storeB']}>
<InnerComponent />
</FluxComponent>
Keeping the Flux architecture (it uses Facebook's Flux behind the scenes) will hopefully make it easy to use other technologies like GraphQL.