When I'm sharing data among components should I call that data only once and provide it as #Input() or should I call that data again on every component's cycle?
For example, I have the following components in one page:
<game-info [id]="params?.id"></game-info>
<game-leaderboard [uid]="auth" [id]="params?.id"></game-leaderboard>
<game-progress [uid]="auth" [id]="params?.id"></game-progress>
Where I get the id from the ActivatedRoute and the uid from my authentication service. In some cases, I'm also passing a data input for multiple components in the same page.
One problem I face is that, sometimes, I'm passing data to many children components and it was harder to debug. For example:
game.component.html
<game-details [data]="data"></game-details>
<game-progress [data]="data"></game-progress>
Then, on details.component.html, I'd pass data as an input to another component - and so on. It became a really long chain:
<game-info [data]="data"></game-info>
<game-players [id]="(data | async)?.$key></game-players>
Is it a proper approach? Or would it be better to get those parameters inside of every component?
Another issue, for example, sometimes I need to get the an async parameter (e.g. uid from an Observable) during onInit but it didn't receive it yet. So, I was wondering if I should just call those parameters straight in the component instead of passing them as an input.
PS. I'm not sure if this is off-topic. If so, please feel free to remove it.
Nothing wrong with that approach. Actually, this is 1 of the recommended ways nowadays where your top-level 'smart' components would gather the data and then inject that data to your 'presentational' aka 'view' aka 'dumb' components. Note that data also flows the other way around: all Events are emitted upwards, where they are handled by the containing 'smart' component. See here for a good (better) explanation.
I must say this approach has been working very well for me: code is clean (clear responsibilities, reusability and testability of presentational components...) although I must admit I share your concern that it might become a bit tedious when you have quite a lot of nested components.
A common approach would be using it as a Injectable service.
For its benefits, as it says:
The component can create the dependency, typically using the new
operator. The component can look up the dependency, by referring to a
global variable. The component can have the dependency passed to it
where it is needed.
For angular 1, check https://docs.angularjs.org/guide/di
For angular 2, check the first answer in What's the best way to inject one service into another in angular 2 (Beta)?
It is hard to answer the question since I am not sure exactly what you are trying to achieve but it might be worth looking into services. Services will have one shared space for the components under the component it is declared under(example the app.component or even app.mudule). Then you can pass the new parameters to other components through the service. That would be the proper way of having a shared state and you can pass through many components by just injecting the service.
Related
I have some trouble with component communication. Lets say I have 3 nested components.
Parent {{component-a}} -> which has child {{component-b}} -> which has child {{component-c}}.
How can I access component-c directly from component-a, if component-c is not rendered.
Is this even possible.
Thank you
Ember uses a data down action up pattern. This means that if you want to send data from a component to its child you pass it by a parameter, but if you want the opposite direction you should send an action with the data. And when you have 3 components you pass by the one in the middle and this one will keep on relaying the information.
You can find more information here
You'll generally want to use a service for communication across different trees of components or for 'sending data up from a child component'
Services are very easy to test.
Using data-down-actions-up would also work, but beyond a couple layers is known as prop drilling. Prop drilling makes components hard to maintain due to over-inter-connectness
Hope this helps!
I Am new to angular2. Trying to understand the usage of #Input in a better way. We can pass values from parent component to child using #Input also we can create a service variable and inject it to the parent component and can access them in child components. Which way would be better? I am getting these values through route resolves. I am feeling skeptical to use #Input when there is no binding of it with user input.
Generally there are two types of components - Presentational and Container or also sometimes called stateful and stateless. Here is the expert from this article explaining the difference:
Presentational components:
Are concerned with how things look.
Receive data and callbacks exclusively via props.
Rarely have their own state (when they do, it’s UI state rather than data).
Container components:
Are concerned with how things work.
Provide the data and behavior to presentational or other container components.
Are often stateful, as they tend to serve as data sources.
Presentational components should receive as much data as possible in a declarative way through input bindings. Container components should use DI as much as possible.
I'm just guessing but like anything it depends on the use case.
If your child component is acting like a stateless component but depends on the data the parent container has state-like access then you'd probable want to use input to pass down the data to the child components.
For example one case that comes to mind is the use of form groups and formcontrols
which the container keeps track of sort of the formgroup logic/state and on submit if the form is reactive will send a data object back or least should.
I'm not familiar myself but the use case for input that makes sense is when you have just rendering visual components that need just some data referenced from the parent container.
hope that makes sense. :) or least shed light on one use case hehe
http://learnangular2.com/inputs/
"most developers need to know how to pass data into components to dynamically configure them."
another good pictoral guide: https://www.sitepoint.com/angular-2-components-inputs-outputs/
Well, to be precise #Input() has nothing to do with user input as you think. It is basically used for passing data from parent component to child component. I agree that the name Input() leads to confusion, but its usage is different. Coming to service injection, this is not related to parent-child. Components at any hierarchy can inject services independently as they need. To conclude it, best method to pass data from parent to child is using #Input().
I have a dropdown <select>-based component that I'd like to be able to drop into any template in the hierarchy of my ember app.
This displays a list of all the Articles (the model) on the site. Whenever I use this component though, the route that I'm in needs to load the data and get passed to the template.
Question :
How can I load this data once and only when the component is rendered?
Also I've been reading this and still have yet to come up with a good solution. I'd like the component to provide the data source, but that seems to be frowned upon.
Would it be terrible to just do an ajax request in my component pre-render?
If you are going to need data preloaded then you can use the initializers to do that for you. You can use this data and inject to any controller , route or all of them if you want. This is a more maintainable way.
For your case you can have a particular controller have articles injected into. Then use this controller data using needs in other required controllers and thus into components.
In this way you have data available for all instance of component. Passing an store object inside the component is mostly an anti-pattern ( depends upon use cases though ) .
Component should be free from headache of data gathering and should focus on logic and presentation.
If want to know more about how to use initializers you can find it here
I am a bit confused by the statements: "Renders the whole application" and "Passing state to child components".
Example 1:
I have a todos app with a AppComponent and TodosListComponent. The AppComponent grabs the array of todos from the store and passes it as a property to the TodosListComponent.
Example 2:
I have a huge application with lots state. I have like 50 components building up my app. Do I want to pass all the state from the stores from AppComponent down through all the 50 components?
So I am wondering, what is the convention? It makes more sense to me to let individual components listen directly to the stores they care about. The advantage is that only individual components rerender, but why then the concept of "the whole application rerender on state change"?
What are the pros and cons of each? What is the common convention?
There are a few ways you can handle this. I think they're all valid and have their own trade-offs.
Get all the state and pass pieces of it to children
This is the technique you specifically asked about. Using this method, you'll have some function or method available to your top-level component that turns all the data from the stores into a "big bag of state" and then you'll selectively pass pieces of this data to child components. If those components have their own children, they'll pass it along as necessary.
The upside to this method is that it makes things generally easy to debug. If you have to change the way a piece of state is retrieved from a store, you only have to change it in the top-level component—as long as it gets passed down with the same name, the other components will "just work." If some piece of data is wrong, you should only need to look in one place to figure out why.
The downside to this technique what I call "props explosion"—you can end up passing a lot of properties around. I use this method in a medium-sized flux application, and a snippet of the top-level application component looks like this:
<section id="col-left">
<Filters loading={this.state.loading}
events={this.state.events}
playbackRate={this.state.videoPlayback.playbackRate}
autoPlayAudio={this.state.audioPlayback.autoPlay}
role={this.state.role} />
</section>
<section id="col-center" className={leftPaneActive ? "" : "inactive"}>
<SessionVideo videoUuid={this.state.session.recording_uuid}
lowQualityVideo={this.state.session.low_quality_video_exists}
playbackRate={this.state.videoPlayback.playbackRate} />
<section id="transcript">
<Transcript loading={this.state.loading}
events={this.state.events}
currentEvents={this.state.currentEvents}
selection={this.state.selection}
users={this.state.session.enrolled_users}
confirmedHcs={this.state.ui.confirmedHcs}
currentTime={this.state.videoPlayback.position}
playing={this.state.videoPlayback.playing} />
</section>
</section>
In particular, there can be a lot of components between the top-level one and some eventual child that do nothing with the data except pass it along, more closely coupling those components to their position in the hierarchy.
Overall, I like the debuggability this technique provides, though as the application grew larger and more complex I found it was not idea to do this with only a single top-level component.
Get all the state and pass it as one object
One of the developers at Facebook mentioned this technique. Here, you'll get a big bag of state, just as above, but you'll pass the whole thing (or entire sub-sections of it) rather than individual properties. By utilizing React.PropTypes.shape in child components, you can ensure that the right properties are getting passed.
The upside is you pass way fewer properties around; the above example might look more like this:
<section id="col-left">
<Filters state={this.state} />
</section>
<section id="col-center" className={leftPaneActive ? "" : "inactive"}>
<SessionVideo session={this.state.session}
playback={this.state.videoPlayback} />
<section id="transcript">
<Transcript state={this.state} />
</section>
</section>
The downside is that it becomes a little more difficult to deal with changes in the shape of the state; rather than just changing the top-level component, you'll have to track down everywhere that piece of data is used and change the way that component access the property. Also, shouldComponentUpdate can potentially become a little trickier to implement.
Allow components to get their own state
On the other end of the spectrum, you can grant application-specific (that is, non-reusable) child components to access the stores and build up their own state based on the store change events. Components that build their own state like this are sometimes called "controller-views" or, more commonly these days, "container components."
The upside, of course, is that you don't have to deal with passing properties around at all (other than change handlers and properties for more reusable components).
The downside, though, is that your components are more highly coupled to the stores—changing the stores or the data they provide (or the interface via which they provide that data) may force you to revisit the code for a larger number of components.
Also, as mentioned in the comments, this can potentially make server rendering a bit more difficult. If you only use properties (especially at only the top level), you can transport them more easily to the client and re-initialize React with the same properties. By allowing the stores to determine their own data, you need to somehow inject that data into the stores to allow the components to get that data.
A common approach, and one that I typically use now, is to make every component in your application only rely on props for global application state, and then decide if it makes more sense to (1) connect them directly to flux by wrapping them in a container, or (2) allow the props to be passed from some parent container.
There are abstractions that you might be able to use to make some of these techniques more viable. For example, a Facebook dev had this to say in a comment on Hacker News:
Now all your data is in stores, but how do you get it into the specific component that needs it? We started with large top level components which pull all the data needed for their children, and pass it down through props. This leads to a lot of cruft and irrelevant code in the intermediate components. What we settled on, for the most part, is components declaring and fetching the data they need themselves, except for some small, more generic components. Since most of our data is fetched asynchronously and cached, we've created mixins that make it easy to declare which data your component needs, and hook the fetching and listening for updates into the lifecycle methods (componentWillMount, etc).
Jason Bonta from Facebook explained the concept of "Containers" in his React.js Conf 2015 talk.
To summarize: containers are simply components that wrap other components, and take care of any data-related concerns such as talking to stores, while the underlying component is focused solely on the view (markup/styles/etc.) and doesn't care where the data comes from.
This makes the component
highly re-usable because it can be wrapped with a different container when data needs to come from a different place,
not contain irrelevant state, therefore easier to implement and optimize shouldComponentUpdate, and
using composition rather than mixins for this aligns with what is likely the future of React with ES6, which does not have idiomatic mixins.
UPDATE March 2019: Look into React Hooks. With hooks, you can accomplish the same goal as described above, but abstract data-related concerns, such as talking to stores, in re-usable chunks of code that can be applied to multiple components. The ReactConf talk React Today and Tomorrow and 90% Cleaner React With Hooks by Dan Abramov does a great job of explaining hooks, and how they are different from both mixins and past composition approaches.
The following is from an issue I posted on EmberJS GitHub, but Stack Overflow is better suited for a discussion than GitHub.
I am building a few complex components at the moment including composite components and I hit a roadblock with the extreme isolation components live in.
There are several cases where I don't need the components to trigger an action on a controller, but where a controller needs to trigger a behaviour change on the component.
Problems is that the components don't know about the controller and the controller is not creating the components either: they are defined in a template.
I kind of solved the problem by subclassing the Ember.Component class to offer a way for messages to get through components.
The new component subclass breaks the on purpose isolation of components that shouldn't know about the outer controller.
The 2 less invasive options I found to make component methods calls from outside are:
Cache component / name of instance pairs in a global array like
App.components, then call a component method with
App.components['name'].method()
Trigger events from outside, register and handle them in the
components. However in that case I am passing an eventSource object
to the component, often a controller like so: {{my-component
eventSource=controller}}
My question is about how could we solve this problem in the most elegant and less invasive way possible for components ?
For achieving composite components, using the components like lego pieces, it seems impossible to me at the moment to see how we can achieve that goal without breaking the components isolation.
Any input, ideas, solutions, discussion is very welcome.
Note: By the way, the first method that breaks the component isolation is inspired by the work done on the ember-bootstrap components: https://github.com/ember-addons/bootstrap-for-ember
The author had to solve the same problem of being capable of triggering methods inside the components from outside.
Another note: Just for the record, another way to access a component is to use Ember.View.views['name'] where name is a view name you gave to your component. However I feel dirty to make such calls, even more from a controller.
In general, I would try to solve this by binding properties to your component, which could then change according to computed properties or observers based on those properties.
For instance, instead of trying to call a method like deactivate on a component, bind a property such as active to a property in the template:
{{my-component active=formEnabled}}
I'm hesitant to recommend passing an eventSource to components as a general solution (like your {{my-component eventSource=controller}} example). I imagine this could work with a class or mixin that just emits specific events and is tightly coupled with your component, but I'm struggling to come up with a use case that justifies this approach.