Local States (with Apollo) By Oskar Bechtold Local States State? - - PowerPoint PPT Presentation

local states with apollo
SMART_READER_LITE
LIVE PREVIEW

Local States (with Apollo) By Oskar Bechtold Local States State? - - PowerPoint PPT Presentation

Local States (with Apollo) By Oskar Bechtold Local States State? Observable Data Service Flux Redux NGRX Apollo NGXS Types of State A typical web application has the following six types of state:


slide-1
SLIDE 1

Local States (with Apollo)

By Oskar Bechtold

slide-2
SLIDE 2

Local States

  • State?
  • Observable Data Service
  • Flux
  • Redux
  • NGRX
  • Apollo
  • NGXS
slide-3
SLIDE 3

Types of State

A typical web application has the following six types of state:

  • Server state
  • Persistent state
  • The URL and router state
  • Client state
  • Transient client state
  • Local UI state
slide-4
SLIDE 4

State Synchronization

  • The persistent state and the server state store the same

information.

  • So do the client state and the URL.
  • We somehow have to synchronize them.
slide-5
SLIDE 5

Ways to Solve the State Problem

  • Angular Services and RxJS -> Observable Data Service
  • Redux using @angular-redux/store (formlerly ng2-redux)
  • Redux using @ngrx
  • Apollo
  • NGXS
slide-6
SLIDE 6

Stores as Solution for Multiple Problems

Stores are a multi-responsibility solution:

  • Component interaction via the Observable pattern.
  • Client-side cache if needed, to avoid doing repeated Ajax

requests.

  • Temporary UI state, as we fill in a large form or want to

store search criteria in a search form when navigating between router views.

  • Solve the problem of allowing modification of client side

transient data by multiple actors.

slide-7
SLIDE 7

Store Architecture

  • Provide an Observable-like pattern for decoupled

component interaction.

  • Provide a client container for temporary UI state.
  • Provide a cache for avoiding excessive HTTP requests.
  • Provide a solution for concurrent data modification by

multiple actors.

  • Provide a hook for tooling.
  • MVC and CRUD vs Event-sourcing, Commands and CQRS
slide-8
SLIDE 8

Model View Controller and CRUD

https://martinfowler.com/bliki/CQRS.html

slide-9
SLIDE 9

Command Query Responsibility Segregation

https://martinfowler.com/bliki/CQRS.html

slide-10
SLIDE 10

Stores and Tooling

One of the biggest reasons for using a store it's the tooling ecosystem it provides. The tooling is amazing,

  • time traveling debugging,
  • being able to attach a store state to a bug report
  • and hot reloading those are huge features.
slide-11
SLIDE 11

Observable Data Services

slide-12
SLIDE 12

Observable Data Services

The service, that can be named a store can be injected in any place where the data is needed:

export class App { constructor(private todoStore: TodoStore, private uiStateStore: UiStateStore) { } }

slide-13
SLIDE 13

Use an Observable Data Service

<ul id="todo-list"> <li *ngFor="let todo of todoStore.todos | async" > ... </li> </ul>

slide-14
SLIDE 14

Modify the Data of a Service

  • nAddTodo(description) {

this.todoStore.addTodo(newTodo) .subscribe( res => {}, err => { this.uiStateStore.endBackendAction(); } ); }

slide-15
SLIDE 15

Build an Observable Data Service

@Injectable() export class TodoStore { private _todos: BehaviorSubject<List<Todo>> = new BehaviorSubject(List([])); public readonly todos: Observable<List<Todo>> = this._todos.asObservable(); constructor(private todoBackendService: TodoBackendService) { this.loadInitialData(); } ... }

slide-16
SLIDE 16

Writing an Action Method

addTodo(newTodo:Todo):Observable { let obs = this.todoBackendService.saveTodo(newTodo);

  • bs.subscribe(

res => { this._todos.next(this._todos.getValue().push(newTodo)); }); return obs; }

slide-17
SLIDE 17

Example

slide-18
SLIDE 18

Example

Exmple taken from https://blog.nrwl.io/managing-state-in-angular-applications-22b75ef5625f

slide-19
SLIDE 19

Example

slide-20
SLIDE 20

Example

Types of State

  • Backend manages the persistent state (the talks) and the

client state (the filters).

  • The router manages the URL and the router state.
  • WatchService manages the transient client state (watched

talks).

  • The individual components manage the local UI state.
slide-21
SLIDE 21

Example

Problems

  • Syncing Persistent and Server State
  • Syncing URL and Client State
slide-22
SLIDE 22

Example

Mistakes

  • No separated state management from computation and
  • services. Backend talks to the server and manages state.
  • No clearly defined synchronization strategy of the

persistent state and the server.

  • No clearly defined synchronization strategy of client

state and URL.

  • Model is mutable, which makes ensuring any sort of

guarantees difficult.

slide-23
SLIDE 23

https://blog.nrwl.io/managing-state-in-angular-applications-22b75ef5625f

Separated State from Services

slide-24
SLIDE 24

https://blog.nrwl.io/managing-state-in-angular-applications-22b75ef5625f

What About the Router?

slide-25
SLIDE 25

Flux

slide-26
SLIDE 26

The Original Facebook Chat Bug

that originated Flux

  • Problem with the unread

messages counter

  • Systematically

displaying incorrect results:

  • users would see one

unread message, when they click the counter all the messages had already been read

slide-27
SLIDE 27

What is Flux

  • Application architecture from Facebook.
  • Utilizing a unidirectional data flow.
  • More of a pattern rather than a formal framework.
slide-28
SLIDE 28

https://facebook.github.io/flux/docs/in-depth-overview.html

slide-29
SLIDE 29

Redux

slide-30
SLIDE 30

What is Redux

  • Application state manager for JavaScript applications.
  • Keeps the core principles of the Flux-architecture by

having a unidirectional data flow in your application.

  • Where Flux applications traditionally have multiple

stores, Redux applications have only one global, read-only application state.

  • State is calculated by "reducing" over a collection or

stream of actions.

slide-31
SLIDE 31

How does Redux

  • Prevent event soup scenarios caused by event buses.
  • Redux store is a combination of the Command and the

Observable patterns.

  • We dispatch an action into the store, and the store will
  • perate on the data inside the store.
  • Emitter of the action does not know what the store will

do with it.

  • Receiver does not know what triggered the generation of

the new data.

  • CQRS — Command Query Responsibility Segregation
slide-32
SLIDE 32

Redux provides a solution by ensuring that:

  • State is wrapped in a single store.
  • Handles all updates and notifies all subscribers.
  • No need to pass state through entire component tree.
  • All changes are sequentially -> predictable end result

free from unexpected effects and race conditions.

  • State is immutable

○ Change in state results in a totally new version of the state ○ More predictable ○ Look at any previous version of the state ○ Incredible debug experience.

slide-33
SLIDE 33

Three Principles

  • Single source of truth

○ The state of your whole application is stored in an object tree within a single store.

  • State is read-only

○ The only way to change the state is to emit an action, an object describing what happened.

  • Changes are made with pure functions

○ To specify how the state tree is transformed by actions, you write pure reducers.

slide-34
SLIDE 34

https://www.dotnetcurry.com/reactjs/1356/redux-pattern-tutorial

slide-35
SLIDE 35

https://medium.com/@aksudupa11/redux-sagas-714370b61692

Better video: https://gfycat.com/ThreadbareWeepyAlbino

slide-36
SLIDE 36

You Might Not Need Redux

Dan Abramov, Co-author of Redux. People often choose Redux before they need it. “What if our app doesn’t scale without it?” Later, developers frown at the indirection Redux introduced to their code. “Why do I have to touch three files to get a simple feature working?” Why indeed! Finally, don’t forget that you can apply ideas from Redux without using Redux. For example, consider a React component with local state.

slide-37
SLIDE 37

Flux vs Redux

slide-38
SLIDE 38

https://stackoverflow.com/questions/32761316/flux-vs-redux-pros-and-cons-highlights

slide-39
SLIDE 39

http://www.prathapkudupublog.com/2017/04/flux-vs-redux.html

slide-40
SLIDE 40

@angular-redux

slide-41
SLIDE 41

What is @angular-redux?

A set of npm packages to integrate redux store into your Angular 2+ applications.

  • Change processing with RxJS observables.
  • Compile time optimizations with NgModule and

Ahead-of-Time compilation.

  • Integration with the Angular change detector.
slide-42
SLIDE 42
  • @angular-redux/store - Bindings between Redux and Angular
  • @angular-redux/form - Bindings between Angular Forms and

your Redux state

  • @angular-redux/router - Bindings between Angular Router

and your Redux state

slide-43
SLIDE 43

NGRX

slide-44
SLIDE 44

What is NGRX

Reactive State for Angular Store is RxJS powered state management for Angular applications, inspired by Redux. Store is a controlled state container designed to help write performant, consistent applications on top of Angular.

slide-45
SLIDE 45

Key Concepts of NGRX

  • Actions: Unique events dispatched from components and

services.

  • Reducers: State changes are handled by pure functions

that take the current state and the latest action to compute a new state.

  • Selectors: Pure functions to select, derive and compose

pieces of state.

slide-46
SLIDE 46

Angular-redux vs NGRX

angular-redux/store is just bindings around the Redux API (uses Redux). ngrx/store is an RxJS powered state management for Angular applications (inspired by Redux, but do not use it).

slide-47
SLIDE 47

src/app/counter.actions.ts

1. export enum ActionTypes { 2. Increment = '[Counter Component] Increment' , 3. Decrement = '[Counter Component] Decrement' , 4. Reset = '[Counter Component] Reset' , 5. } 6. 7. export class Increment implements Action { readonly type = ActionTypes .Increment; } 8. export class Decrement implements Action { readonly type = ActionTypes .Decrement; } 9. export class Reset implements Action { readonly type = ActionTypes .Reset; }

slide-48
SLIDE 48

src/app/counter.reducer.ts

1. export const initialState = 0; 2. export function counterReducer (state = initialState , action: Action) { 3. switch (action.type) { 4. case ActionTypes .Increment: 5. return state + 1; 6. case ActionTypes .Decrement: 7. return state - 1; 8. case ActionTypes .Reset: 9. return 0; 10. default: 11. return state; 12. } 13. }

slide-49
SLIDE 49

src/app/my-counter/my-counter.component.ts

1. export class MyCounterComponent { 2. count$: Observable <number>; 3. constructor (private store: Store<{ count: number }>) { 4. this.count$ = store.pipe(select('count')); 5. } 6. 7. increment () { this.store.dispatch(new Increment()); } 8. decrement () { this.store.dispatch(new Decrement()); } 9. reset() { this.store.dispatch(new Reset()); } 10. }

slide-50
SLIDE 50

Also cool, Selectors

Selectors are pure functions used for obtaining slices of store state.

slide-51
SLIDE 51

Effects

Provides an API to model event sources as actions. Effects:

  • Listen for actions dispatched from Store.
  • Isolate side effects from components, allowing for more

pure components that select state and dispatch actions.

  • Provide new sources of actions to reduce state based on

external interactions such as network requests, web socket messages and time-based events.

slide-52
SLIDE 52

Plugins

  • Entity State adapter for managing record collections.
  • Router Store.
slide-53
SLIDE 53

Persistence

  • Ngrx-store-persist

○ Whole store persisted

  • Ngrx-store-localstorage

○ Setup with keys to store only parts of the store

slide-54
SLIDE 54

Apollo

slide-55
SLIDE 55

THE GRAPHQL PLATFORM

Do GraphQL Right

  • Replace many inflexible

APIs with a single versatile query system.

  • Decouple frontend and

backend development.

  • Ship high quality apps

to more platforms faster.

slide-56
SLIDE 56

GraphQL

  • GraphQL is a query language for your API,
  • and a server-side runtime for executing queries
  • by using a type system you define for your data.
slide-57
SLIDE 57

At its simplest, GraphQL is about asking for specific fields

  • n objects

Query { hero { name } } JSON Result { "data": { "hero": { "name": "R2-D2" } } }

slide-58
SLIDE 58

Fields

Query { hero { name # Queries can have comments! friends { name } } } JSON Result { "data": { "hero": { "name": "R2-D2", "friends": [ { "name": "Luke Skywalker" }, { "name": "Han Solo" }, { "name": "Leia Organa" } ] } } }

slide-59
SLIDE 59

Arguments

Query { human(id: "1000") { name height } } JSON Result { "data": { "human": { "name": "Luke Skywalker", "height": 1.72 } } }

slide-60
SLIDE 60

Mutations

mutation CreateReviewForEpisode($ep: Episode!, $review: ReviewInput!) { createReview(episode: $ep, review: $review) { stars commentary } }

slide-61
SLIDE 61

https://www.howtographql.com/basics/1-graphql-is-the-better-rest/

GraphQL is the better REST

slide-62
SLIDE 62

https://www.apollographql.com/docs/tutorial/introduction.html

slide-63
SLIDE 63

Apollo GraphQL Query

const CurrentUserForProfile = gql` query CurrentUserForProfile { currentUser { login avatar_url } } `; this.querySubscription = this.apollo.watchQuery<any>({ query: CurrentUserForProfile }) .valueChanges .subscribe(({ data, loading }) => { this.loading = loading; this.currentUser = data.currentUser; });

slide-64
SLIDE 64

Apollo GraphQL Mutation

const submitRepository = gql` mutation submitRepository { submitRepository(repoFullName: "apollographql/apollo-client") { createdAt } } `;

<

newRepository() { this.apollo.mutate({ mutation: submitRepository }).subscribe(); }

slide-65
SLIDE 65

Apollo Cache

  • apollo-cache-inmemory is the default cache

implementation.

  • InMemoryCache is a normalized data store without the

dependency on Redux.

  • Sometimes you may need to manipulate the cache directly,

such as updating the store after a mutation.

slide-66
SLIDE 66

Local state management

  • So far remote data from our GraphQL server.
  • Access boolean flags and device API results from multiple

components in our app, without maintaining a separate NGRX or Redux store.

  • Apollo cache can be the single source of truth for all

data in the client application.

  • apollo-link-state allows you to store your local data

inside the Apollo cache alongside your remote data.

slide-67
SLIDE 67

Setup

@NgModule({ // ... providers: [{ provide: APOLLO_OPTIONS, useFactory(httpLink: HttpLink) { const cache = new InMemoryCache(); const http = httpLink.create({ uri: "https://w5xlvm3vzz.lp.gql.zone/graphql" }); const local = withClientState({ cache, defaults, resolvers }); return { cache: new InMemoryCache(), link: local.concat(http) } }, deps: [HttpLink] }], // ... }) export class AppModule {}

slide-68
SLIDE 68

Resolvers

export const resolvers = { Mutation: { toggleTodo: (_, variables, {cache, getCacheKey}) => { const id = getCacheKey({__typename: 'TodoItem', id: variables.id}); const fragment = gql` fragment completeTodo on TodoItem { completed } `; const todo = cache.readFragment({fragment, id}); const data = {...todo, completed: !todo.completed}; cache.writeData({id, data}); return null; }, }, };

slide-69
SLIDE 69

Optimistic UI

const updateComment = gql` mutation updateComment($commentId: ID!, $commentContent: String!) { updateComment(commentId: $commentId, commentContent: $commentContent) { id __typename content } } `; submit({ commentId, commentContent }) { this.apollo.mutate({ variables: { commentId, commentContent },

  • ptimisticResponse: {

__typename: 'Mutation', updateComment: { id: commentId, __typename: 'Comment', content: commentContent, }, }, }).subscribe(); }

slide-70
SLIDE 70

Persistence

  • Apollo-cache-persist
  • Just tell it where to store the store
  • In conflict with defaults
slide-71
SLIDE 71

NGXS

slide-72
SLIDE 72

NGXS

  • State management pattern + library.
  • CQRS like Redux and NGRX.
  • But less boilerplate by using modern TypeScript features

such as classes and decorators.

slide-73
SLIDE 73

Concepts

  • Store

○ Global state container, action dispatcher and selector

  • Actions

○ Class describing action to take

  • State

○ Class definition of the state

  • Select

○ State slice selectors

slide-74
SLIDE 74

https://ngxs.gitbook.io/ngxs/concepts/intro

slide-75
SLIDE 75
  • Logger
  • Devtools
  • Storage
  • Forms
  • Web Socket
  • Router

Plugins

slide-76
SLIDE 76

Summary

  • Observable Data Services

○ Easy, can get messy, CRUD

  • Flux

○ Just a pattern, one store per module/component, lot’s to code, CQRS

  • Redux

○ One store per app, write actions and reducers, awesome devtools, CQRS

  • Apollo

○ GraphQl for queries and mutations, write resolvers, devtools, CRUD

  • NGXS

○ One store, apparently less boilerplate code, redux devtools, CQRS

slide-77
SLIDE 77

Code Examples

  • https://stackblitz.com/edit/angular-local-state-ngrx
  • https://stackblitz.com/edit/angular-local-state-ngxs
  • https://stackblitz.com/edit/angular-local-state-apollo
  • Enabled Devtools for all three:
  • http://extension.remotedev.io/
  • https://chrome.google.com/webstore/detail/apollo-client-d

eveloper-t/jdkknkkbebbapilgoeccciglkfbmbnfm

slide-78
SLIDE 78

Sources

  • https://almerosteyn.com/2016/08/redux-explained-again
  • https://angular-2-training-book.rangle.io/handout/state-m

anagement/

  • https://blog.angular-university.io/angular-2-redux-ngrx-r

xjs/

  • https://blog.angular-university.io/how-to-build-angular2-

apps-using-rxjs-observable-data-services-pitfalls-to-avoi d/

  • https://vsavkin.com/managing-state-in-angular-2-applicati
  • ns-caf78d123d02
slide-79
SLIDE 79

Sources

  • https://blog.angular-university.io/angular-ngrx-store-and
  • effects-crash-course/
  • https://facebook.github.io/flux/docs/in-depth-overview.ht

ml

  • https://redux.js.org/basics/dataflow
  • https://ngrx.io/
  • https://github.com/angular-redux/platform
  • https://julienrenaux.fr/2017/02/16/from-redux-to-angular-

ngrxstore/