Sharing state between components is one of the most important aspects of UI development. The counter application example below shows how Vue, Angular and React have a few options in implementing state sharing across components. For more complex state management, each of them have a corresponding popular library (NgRx, Redux, Vuex) that I will discuss in a separate posts.
Counter App
The counter has three components to demonstrate the state sharing:
- The App component that shows all count values from different components. localCount is defined to give a comparison between a local state (localCount) and a shared state (count).
- child component is a child of the main app component
- sibling component is the sibling of child component
- count variable is the state value that is passed either to child (direct inheritance) or sibling(indirect sharing) component
Vue
In Vue, we can use:
- props - count property value is passed down from the parent component. Props is a great way to keep components in it's simplest form, the defining aspect of a stateless components - ChildCount component
- EventBus - basically a Vue instance without DOM attachments. This global event broadcast can be used to share state values to listeners. Overusing this will lead to "event soup"
- With Vue reactivity, we can have a simple store object that triggers update when the store object mutated - use with caution: when things get complex, object mutation can lead to bugs and unintended actions.
React
In React, we can use:
- props - count property value is passed down from the parent component. Props is a great way to keep components in it's simplest form, the defining aspect of a stateless components - ChildCount component
- Context - it defines the count state inside the CountProvider. CountContext.Provider provides the count value to its children. useContext hook is then used in children acting as the consumers that need the count value: App component and SiblingValue
Angular
- @Input is the equivalent of props property in Angular
- Angular Service implements the dependency injection pattern to share state across components. By making the service reactive using Observable and Subject, count property is available to consume by SiblingCount component. The use of async is always the best practice in Angular which provides automatic unsubscribe action when the component is destroyed.
Top comments (1)
Nice comparison of state management for these simple examples. In my mind the only way to sanely tackle state management once your example goes any more complex is to use centralize datastore like Vuex/Redux.