extending redux in the server side
TRANSCRIPT
![Page 1: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/1.jpg)
Nacho Martín @nacmartin
AgentConf January 2018
Extending Redux in the Server Side
![Page 2: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/2.jpg)
Nacho Martín (Spanish parents do actually pick this name for their kids)
I write code at Limenius.
We build tailor-made projects, and provide consultancy and formation.
We organize React Alicante.
And we are very happy with React and React Native.
![Page 3: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/3.jpg)
http://slides.com/jenyaterpil/redux-from-twitter-hype-to-production#/
![Page 4: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/4.jpg)
http://slides.com/jenyaterpil/redux-from-twitter-hype-to-production#/
![Page 5: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/5.jpg)
Redux: Three principles
The state of the whole application is stored in an object tree within a single store.
The only way to change the state is to emit an action, an object describing what happened.
To specify how the state tree is transformed by actions, you write pure reducers.
![Page 6: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/6.jpg)
Redux as async reduce
state = actions.reduce(reducer, initialState)
newState = reducer(action, state)
![Page 7: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/7.jpg)
A particular way of thinking.
Useful to model certain problems.
What are we going to talk about
![Page 9: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/9.jpg)
![Page 10: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/10.jpg)
PLAN
TERRITORY&
![Page 11: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/11.jpg)
Typical case
Create
Read
Update
Delete
If my DB has…
![Page 12: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/12.jpg)
Typical case
Create
Read
Update
Delete
If my DB has… …and my REST API has…
POST
GET
PUT
DELETE+
![Page 13: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/13.jpg)
Typical case
Create
Read
Update
Delete
If my DB has… …and my REST API has…
POST
GET
PUT
DELETE+ =
…my project will be…
![Page 15: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/15.jpg)
“Chat tutorial paradigm”
SENDHi there! SEND
SERVERemit(‘chat_message’, ‘hi there!’)
(Whenever there is a websocket)
![Page 16: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/16.jpg)
“Chat tutorial paradigm”
SEND SEND
SERVERemit(‘chat_message’, ‘hi there!’)
socket.on(‘chat_message', function(msg){ io.emit(‘chat_message', msg); });
(Whenever there is a websocket)
![Page 17: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/17.jpg)
“Chat tutorial paradigm”
SEND SEND
Hi there!
SERVERemit(‘chat_message’, ‘hi there!’)
socket.on(‘chat_message', function(msg){ io.emit(‘chat_message', msg); });
socket.on(‘chat_message', function(msg){ addMessage(msg)); });
(Whenever there is a websocket)
![Page 18: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/18.jpg)
Typically we also want
SEND SEND
Hi there!
SERVERemit(‘chat_message’, ‘hi there!’)
socket.on(‘chat_message', function(msg){ io.emit(‘chat_message', msg); });
socket.on(‘chat_message', function(msg){ addMessage(msg)); });
store(‘hi there!’)
![Page 20: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/20.jpg)
Multiple users manipulate the same resource.
And they need to be notified in real time of the changes.
Our particular case study
Editor for nutritionists that several users can manipulate in collaboration.
Games (cards, domino, quizzes…).
![Page 21: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/21.jpg)
Example: Quiz Game (Multiplayer)
User picks answer 3
Mark answer as selected
SERVER CLIENTCLIENT
State State’ State
![Page 22: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/22.jpg)
Example: Quiz Game (Multiplayer)
User picks answer 3
Mark answer as selected
SERVER CLIENTCLIENT
State State’ State
{type: answer answer:3}
Event
![Page 23: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/23.jpg)
Example: Quiz Game (Multiplayer)
User picks answer 3Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?
Mark answer as selected
SERVER CLIENTCLIENT
State State’ State
{type: answer answer:3}
Event
![Page 24: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/24.jpg)
Example: Quiz Game (Multiplayer)
User picks answer 3
Event’
Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?
Mark answer as selected
SERVER CLIENTCLIENT
State State’ State
{type: answer answer:3}
{type: answer player: 1, answer:3, correct: false}
Event
![Page 25: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/25.jpg)
Example: Quiz Game (Multiplayer)
User picks answer 3
Event’
Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?
Mark answer as selected
SERVER CLIENTCLIENT
State State’ State
{type: answer answer:3}
{type: answer player: 1, answer:3, correct: false}
Event
Mark answer as selected
![Page 26: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/26.jpg)
Example: Quiz Game (Multiplayer)
User picks answer 3Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?
Mark answer as selected
SERVER CLIENTCLIENT
State State’ State
{type: answer answer:3}
Event
![Page 27: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/27.jpg)
Example: Quiz Game (Multiplayer)
User picks answer 3
Event’
Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?
Mark answer as selected
SERVER CLIENTCLIENT
State State’ State
{type: answer answer:3}
{type: new_question question: q}
Event
![Page 28: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/28.jpg)
Example: Quiz Game (Multiplayer)
User picks answer 3
Event’
Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?
Mark answer as selected
SERVER CLIENTCLIENT
State State’ State
{type: answer answer:3}
{type: new_question question: q}
Event
Change question
![Page 29: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/29.jpg)
Example: Quiz Game (Multiplayer)
User picks answer 3Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?
Mark answer as selected
SERVER CLIENTCLIENT
State State’ State
{type: answer answer:3}
Event
![Page 30: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/30.jpg)
Example: Quiz Game (Multiplayer)
User picks answer 3
Event’
Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?
Mark answer as selected
SERVER CLIENTCLIENT
State State’ State
{type: answer answer:3}
{type: new_scores scores: sc}
Event
![Page 31: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/31.jpg)
Example: Quiz Game (Multiplayer)
User picks answer 3
Event’
Is the answer correct? Has everybody else answered? Should we ask a new question? Is the game over?
Mark answer as selected
SERVER CLIENTCLIENT
State State’ State
{type: answer answer:3}
{type: new_scores scores: sc}
Event
Update scores
![Page 32: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/32.jpg)
Example: Quiz Game (Multiplayer)
Events’
SERVER CLIENT
State State’Events
Two vocabularies of eventsTwo representations of the stateTwo ways of calculating the state
![Page 33: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/33.jpg)
Example: Quiz Game (Multiplayer)
Events’
SERVER CLIENT
State State’Events
Two applications :_(
![Page 34: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/34.jpg)
Best situation
User disconnected! 💀 SERVERCLIENT
State State’🎉
![Page 35: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/35.jpg)
Best situation
User reconnected! SERVERCLIENT
State State’Plz give me the state
![Page 36: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/36.jpg)
Best situation
SERVERCLIENT
State State’{get_state: state}
🎉
![Page 38: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/38.jpg)
SERVER
State
CLIENT
State
CLIENT
State
![Page 39: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/39.jpg)
SERVER
State
CLIENT
State
CLIENT
State
Event
![Page 40: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/40.jpg)
SERVER
State
CLIENT
State
CLIENT
State
Event
Update state
![Page 41: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/41.jpg)
SERVER
State
CLIENT
State
CLIENT
State
Event
State
Update state
State
![Page 42: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/42.jpg)
Making the backend play well with Redux
A part of the client’s Redux state lives in the server.
The client changes it sending events to the server.
The server pushes (slices of) the state to the clients.
![Page 43: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/43.jpg)
Let’s build the simplest example
![Page 44: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/44.jpg)
With Redux directly in node.js
![Page 45: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/45.jpg)
Views
Actions
Reducers
StateStore
![Page 46: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/46.jpg)
Views
Actions
Reducers
StateStore
Events
Store
State
Reducers
Client Server
![Page 47: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/47.jpg)
Views
Actions
Reducers
StateStore
Events
Store
State
Reducers
Client Server
![Page 48: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/48.jpg)
<Grid> {board.map((row, idxRow) => ( <Row idx={idxRow} key={idxRow}> {row.map((tile, idx) => ( <Tile onClick={() => this.socket.emit("game:play", { x: idx, y: idxRow })} key={idx} idx={idx} tile={tile} /> ))} </Row> ))} </Grid>
Client
![Page 49: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/49.jpg)
Views
Actions
Reducers
StateStore
Events
Store
State
Reducers
Client Server
![Page 50: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/50.jpg)
io.on("connection", function(socket) { //… socket.on("game:play", function(data) { store.dispatch({ type: GAME_PLAY, x: data.x, y: data.y }); }); socket.on("game:reset", function(data) { store.dispatch({ type: GAME_RESET }); });});
Server
![Page 51: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/51.jpg)
const reducer = function(state = initialState, action = {}) { switch (action.type) { case GAME_PLAY: const { stateAfterPlayer, waitingForOpponent } = makePlayerMove(state, { x: action.x, y: action.y }); if (!waitingForOpponent) { return stateAfterPlayer; } return makeAIMove(stateAfterPlayer); case GAME_RESET: return initialState; default: return state; }};
Server
![Page 52: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/52.jpg)
Views
Actions
Reducers
StateStore
Events
Store
State
Reducers
Client Server
![Page 53: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/53.jpg)
observeStore( store, state => state, state => { socket.emit("game_update", state) } );
function observeStore(store, select, onChange) { let currentState;
function handleChange() { let nextState = select(store.getState()); if (nextState !== currentState) { currentState = nextState; onChange(currentState); } }
let unsubscribe = store.subscribe(handleChange); handleChange(); return unsubscribe;}
Server
![Page 54: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/54.jpg)
componentDidMount() { const { dispatch } = this.props; let socket = ioClient("http://localhost:3080"); socket.on("game_update", gameState => dispatch(updateGame(gameState))); }
Client
![Page 55: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/55.jpg)
Views
Actions
Reducers
StateStore
Events
Store
State
Reducers
Client Server
![Page 56: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/56.jpg)
export default function reducer(state = initialState, action = {}) { switch (action.type) { case GAME_UPDATE: return { ...state, board: action.game.board, phase: action.game.phase };
default: return state; }}
export function updateGame(game) { return { type: GAME_UPDATE, game };}
Client
![Page 57: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/57.jpg)
Views
Actions
Reducers
StateStore
Events
Store
State
Reducers
Client Server
![Page 58: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/58.jpg)
const mapStateToProps = state => ({ board: state.board, phase: state.phase });
export default connect(mapStateToProps)(Board);
Client
![Page 59: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/59.jpg)
With Elixir OTP
![Page 61: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/61.jpg)
Used in
Databases, gaming, telecom, message passing…
“Erlang is a programming language used to build massively scalable soft real-time systems with requirements on high availability”
![Page 62: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/62.jpg)
![Page 63: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/63.jpg)
😍OPEN TELECOM PLATFORM😍
![Page 64: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/64.jpg)
Supervisor
GenServerGenServerSupervisor
GenServerGenServer GenServer
OTP Supervision trees
![Page 65: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/65.jpg)
Gen Server callbacks
defmodule Tictactoe.GameServer do use GenServer
#Callbacks def init(args) do {:ok, state} end
def handle_cast(request, state) do {:noreply, new_state} endend
state = actions.reduce(reducer, initialState)
newState = reducer(action, state);
![Page 66: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/66.jpg)
Views
Actions
Reducers
StateStore
Events
GenServer
State
Callbacks
Client Server
![Page 67: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/67.jpg)
defmodule TictactoeWeb.GameChannel do use Phoenix.Channel
def join("game", _message, socket) do game = Tictactoe.GameServer.getGameState() {:ok, game, socket} end
def handle_in("game:play", %{"x" => x, "y" => y}, socket) do Tictactoe.GameServer.play(x, y) {:noreply, socket} end
def handle_in("game:reset", _, socket) do Tictactoe.GameServer.reset() {:noreply, socket} endend
![Page 68: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/68.jpg)
def init(:ok) do {:ok, %State{}} end
const reducer = function(state = initialState, action = {}) { switch (action.type) { //… default: return state; }};
![Page 69: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/69.jpg)
const reducer = function(state, action) { switch (action.type) { //.. case GAME_RESET: return initialState; //… }};
def handle_cast(%{:action => :reset}, _state) do state = %State{} Endpoint.broadcast(“game", “game_update", serialize_game(state)) {:noreply, state} end
![Page 70: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/70.jpg)
def handle_cast(%{:action => :play, :x => x, :y => y}, state) do case can_move(state, x, y) do :true -> state1 = put_in state.board[y][x], "X" state2 = state |> check_finished |> make_random_move |> check_finished Endpoint.broadcast( “game", “game_update", serialize_game(state2)) state2 :false -> state end {:noreply, state} end
const reducer = function(state, action) { switch (action.type) { case GAME_PLAY: const { stateAfterPlayer, waitingForOpponent } = makePlayerMove(state, { x: action.x, y: action.y }); if (!waitingForOpponent) { return stateAfterPlayer; } return makeAIMove(stateAf); //.. }};
![Page 71: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/71.jpg)
Demo
https://github.com/Limenius/tictactoe
![Page 72: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/72.jpg)
CAN WE THINK ABOUT THIS
AS AN IN-MEMORY DATABASE? 🤔
by Sindre Aalberg
![Page 73: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/73.jpg)
And can we think about this as Event Sourcing?
CLIENT
State
SERVER
![Page 74: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/74.jpg)
And can we think about this as Event Sourcing?
CLIENT
State
Events
SERVER
![Page 75: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/75.jpg)
And can we think about this as Event Sourcing?
CLIENT
State
Events
SERVERLog
![Page 76: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/76.jpg)
And can we think about this as Event Sourcing?
CLIENT
State
Events
SERVER
View
Log
![Page 77: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/77.jpg)
Queries
And can we think about this as Event Sourcing?
CLIENT
State
Events
SERVER
View
Log
![Page 78: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/78.jpg)
Queries
And can we think about this as Event Sourcing?
CLIENT
State
Events
SERVER
View
Log
Another view
![Page 79: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/79.jpg)
Queries
And can we think about this as Event Sourcing?
CLIENT
State
Events
SERVERLog
Another view
View (State)
![Page 80: Extending Redux in the Server Side](https://reader031.vdocument.in/reader031/viewer/2022030318/5aabf7517f8b9a893c8b494d/html5/thumbnails/80.jpg)
And can we think about this as Event Sourcing?
CLIENT
State
Events
Subscribe
SERVERLog
Another view
View (State)