-
Notifications
You must be signed in to change notification settings - Fork 3
Replacing a child component when state changes
Nathan Ridley edited this page Aug 6, 2016
·
1 revision
Sometimes we want to be able to switch out one component for another depending on the state of our application. A simple example would be changing a login form in the sidebar to a profile picture and account menu if the user is logged in. Obviously this isn't too difficult to handle manually, but using a collection can make it a breeze.
This example assumes the existence of an auth$
source stream. The hypothetical stream emits {profile: null}
if not logged in, or {profile: {...}}
otherwise, and uses @most/hold
to retain the last emitted value so that when the stream is observed by a new component, it'll receive the most recent auth state straight away.
function LoginForm(sources) {
// ...
return { DOM: view$ };
}
function AccountControls(sources) {
// ...
return { DOM: view$ };
}
function App(sources) {
const components$ = sources.auth$
// Filter out values where the login state has not changed. Emitting a value
// past this point causes the component to be recreated and replaced in the
// collection. Seeing as the component will itself observe the auth$ source,
// it will take care of reacting to secondary changes to auth information.
.skipRepeatsWith((a, b) => !a.profile === !b.profile)
// Use `scan` to initialize a new collection and keep track of the child
// component that will be swapped out depending on login state.
.scan((components, auth) => {
const account = a.profile ? AccountControls(sources) : LoginForm(sources);
return components.setInstance('account', account);
}, Collection())
// Skip the initial blank collection that `scan` will emit first
.skip(1);
// At this point we could perform further operations to append and manage
// more child components in the list as well. Alternatively or additionally,
// we could pre-initialize the collection with the components that we know
// won't be changing externally.
// ...
// Because we have a stream of collections, rather than access to the
// collection itself, we can use the static equivalents of the available
// 'emit' functions:
const view$ = Collection
.combineObject('DOM', components$)
.map(({accountView}) => render(accountView));
return {
DOM: view$
};
}
- [Managing child components](Managing child components)
- [Replacing a child component when state changes](Replacing a child component when state changes)
- [Combining multiple sinks from child components](Combining multiple sinks from child components)
- [Simple merging of a common sink to a derivative stream](Simple merging of a common sink to a derivative stream)
- [Dynamic lists of child components](Dynamic lists of child components)
- [Managing lists of components that don't have a key](Managing lists of components that don't have a key)
- [Handling multiple component types in a single list](Handling multiple component types in a single list)
- [Taking control of a component's lifecycle within a list](Taking control of a component's lifecycle within a list)
API Reference
- [Quick Reference](API Quick Reference)
- [Detailed Reference](API Detailed Reference)