Dan Abramov - Live React: Hot Reloading with Time Travel at react-europe 2015

By: ReactEurope

3658   19   273996

Uploaded on 07/05/2015

React’s unique strength is bringing to JavaScript development some of the benefits previously exclusive to more radically functional languages such as Elm and ClojureScript, without forcing you to completely eschew local state or rewrite code with exclusively immutable data structures. In this talk, Dan will demonstrate how React can be used together with Webpack Hot Module Replacement to create a live editing environment with time travel that supercharges your debugging experience and transforms the way you work on real apps every day.

Comments (9):

By stankot    2017-09-20

Hey there,

I'll start with the disclaimer, as lately HN comments have tendency of becoming toxic - everything I write is my personal opinion.

With that behind us I can start. I'll try to write this for someone who knows very little about JS, but knows her/his way around basic programming/cs.

Firstly I love JavaScript, I have been writing it for 10 years now, but there are bad parts of it as well.

Let's start with good stuff

* It is evolving in the right direction

* You can do a lot of things with it (web apps, games, mobile apps, server...)

* Materials for learning are everywhere

* It will be easy to find a job

Bad stuff

* It is moving at crazy to follow pace

* There are a lot of different ways of doing same things

* As it is very hip thing to do, there is a lot of bu___hit (beware of the hype train)

Learn plain javascript before moving to frameworks. Focus on ES6 and new stuff as it will make your life way easier.

* Someone already mentioned Dr. Axel Rauschmayer, pick any of his books - http://exploringjs.com/

* Another good one is You Dont Know JS - https://github.com/getify/You-Dont-Know-JS

Try to make small app on your own. You'll get into all sort of problems, but that's the fun part I guess. That will help you to understand what frameworks are trying to solve.

Then you can start learning one of the frameworks. React, Vue, Angular are all solid choices. My pick is React, as I know it best. Apply the same mindset as with learning plain JS. Try to write your own stuff on a small scale before importing huge libraries.

Good example is redux, everybody on the internet are screaming that you should always use it, but even Dan Abramov (author of redux) has great read - You might not need redux https://medium.com/@dan_abramov/you-might-not-need-redux-be4...

Try handling state yourself, then if you see that you need big guns, try redux. Same goes for any big library or technology.

So, buckle up, do it thoroughly and try to find fun in doing javascript. And the most important generic advice - do a real pet project instead of just blindly following tutorials.

This will take some time, and if you just want enough knowledge to lend a job, pick a framework, throw yourself into the deep end and swim your way out. This is something I wouldn't recommend but it works for some people.

Hope this helps, cheers! S

P.S.

Random JS talks I like

* Wat - Gary Bernhardt, 2012 https://www.destroyallsoftware.com/talks/wat It never fails to crack me up

* Live React: Hot Reloading with Time Travel - Dan Abramov, 2015 https://www.youtube.com/watch?v=xsSnOQynTHs Classic nowadays, it is a delight to watch Dan Abramov presenting, only thing missing is a mic drop at the end

* What the heck is the event loop anyway? - Philip Roberts, 2014 https://www.youtube.com/watch?v=8aGhZQkoFbQ This is a must watch for every js developer

EDIT: Sorry for the formatting, HN doesn't support markdown

Original Thread

By breatheoften    2017-10-27

Is Apollo good? I feel like I’ve been aware of their existence for a long time — they have a large marketing presence but I don’t actually have any idea what it is ... there’s a server for making graphql servers and a client for doing ...??? I know they have tools for compiling graphql queries into various typed language interfaces which I have lusted for.

I feel like every blog post of theirs I’ve ever clicked is high percentage marketing and not a lot of focused explanation ...

They have a tough communication nut to crack — they have to sell to people who’ve never heard of graphql, to people who’ve lusted after the vision communicated very clearly by Facebook for graphql and relay, to people using redux and the disarray of different mechanisms for straddling the various in practice divides between local and server state.

Being able to map rest apis into graphql apis on the browser side seems like a nice migration strategy but there still seems like something missing to me to feel like I know what the value proposition of the Apollo Client is ...

Are there any good live demo style introductions to Apollo — something gripping like the original redux conference demo[1] ...?

[1] https://youtu.be/xsSnOQynTHs

Original Thread

By anonymous    2017-09-20

Who does it

You will find a lot interesting things in the React and ELM communities, and in frontend functional programming communities in general.

Some recent full-stack platforms that are somehow trying to provide a development environment of this kind are:

Eve:

A Andreessen Horowitz / Y-Combinator startup, 2.3 million funded, from Chris Granger, an influent Clojure programmer who already built LightTables.

Technologies: Rust (backend), TypeScript (frontend) with a home-made implementation of React concepts (what they call "microReact")

Unison:

Not a company (yet?) but supported by a Patreon campaign, from Paul Chiusano (author of famous book "FP in Scala").

Technologies: Haskell (backend), ELM (frontend).


Note: you can see that the guys behind these tools are experienced functional programmers. Check "how it works" section.


How it works -> functional programming

Programs have state.

Why was Bret Victor's able to make that video?

Because:

  • his architecture is explicit about state mutations
  • he uses functional purity
  • he record historical facts as state, rather than current UI state

One tool inspired by this talk is the ELM language.

ELM states that:

So at the root of the debugger is the design of Elm itself. If you do not start with the right design choices at the language level, creating a time-traveling debugger quickly becomes extremely complex. Even languages that partially fulfill the necessary design requirements will have serious challenges.

So what you really have to understand is that it is not the technology that is interesting, but the underlying software architecture. Once you have the architecture, it is not so hard to add such debugging features.

Many in the ReactJS/Flux communities have shown that we can achieve really great things with this kind of architecture. David Nolen of Om's ClojureScript hype is probably the trigger, and Dan Abramov has shown recently that we can achieve very similar things that compare to Bret Victor's debugging.

Myself I've been experimenting with recording user session videos in JSON, which is also a feature that is leveraged by this kind of architecture.


So, you have to understand that what he achieves is not done by clever code tricks or a super language, but really good architectural patterns.

These patterns are not even new, they are used by database creators and some backend developers for a very long time under different names, including command/event sourcing, journaling... If you want an introduction, the Confluent.IO blog is a very pedagogic source.


The problem is not even about reloading code, it is all about what to do with the state after the code has been reloaded.

What you really need to understand is that there's no unique answer to that question: it all depends on what you want to achieve.

For example in Bret Victor's example with Mario, when he modifies some parameter like the gravity, you can see that it can affect both the past (what he has recorded) and the future (the actions he'll do after the code change). This means that the user intent is reinterpreted in a different context, producing a new history of facts (often called command-sourcing).

While this is really interesting for video games like he has shown, this is absolutely useless for many other applications. Let's take an example of an accountability application, where the tax % can increase or decrease every year. Do you really think modifying the current year tax % should have any effect on the balance sheet of 10 years ago? Obviously not, but it may still have effects on the current year.

Also the Mario positions tray when adjusting the jump parameter, the tool can't know by himself that it has to display it for the Mario element. You have to be explicit about it otherwise it could do the same for the clouds or the turtle. And does it make sense to do the same for the accountability app?

What I mean here is that this is a cool demo, that has been well-produced. You can't get a similar dev environment that work so well out of the box. But you can learn the architectural patterns that permit to do it easily, and use tools like ELM / Om / Redux / Flux / ReactJS (and some Haskell / Scala / Erlang may be useful too!), that will help you greatly in implementing them correctly and provide you the most they can for hot reloading.

Original Thread

By anonymous    2017-09-20

Redux author here!

Redux is not that different from Flux. Overall it has same architecture, but Redux is able to cut some complexity corners by using functional composition where Flux uses callback registration.

There is not a fundamental different in Redux, but I find it that Redux makes certain abstractions easier, or at least possible to implement, that would be hard or impossible to implement in Flux.

Reducer Composition

Take, for example, pagination. My Flux + React Router example handles pagination, but the code for that is awful. One of the reasons it's awful is that Flux makes it unnatural to reuse functionality across stores. If two stores need to handle pagination in response to different actions, they either need to inherit from a common base store (bad! you're locking yourself into a particular design when you use inheritance), or call a function from the handler, which will need to somehow operate on the Flux store's private state. The whole thing is messy (although definitely in the realm of possible).

On the other hand, with Redux pagination is natural thanks to reducer composition. It's reducers all the way down, so you can write a reducer factory that generates pagination reducers and then use it in your reducer tree. The key to why it's so easy is because in Flux, stores are flat, but in Redux, reducers can be nested via functional composition, just like React components can be nested.

This pattern also enables wonderful features like no-user-code undo/redo. Can you imagine plugging Undo/Redo into a Flux app being two lines of code? Hardly. With Redux, it is—again, thanks to reducer composition pattern. I need to highlight there's nothing new about it—this is the pattern pioneered and described in detail in Elm Architecture which was itself influenced by Flux.

Server Rendering

People have been rendering on the server fine with Flux, but seeing that we have 20 Flux libraries each attempting to make server rendering “easier”, perhaps Flux has some rough edges on the server. The truth is Facebook doesn't do much server rendering, so they haven't been very concerned about it, and rely on the ecosystem to make it easier.

In traditional Flux, stores are singletons. This means it's hard to separate the data for different requests on the server. Not impossible, but hard. This is why most Flux libraries (as well as the new Flux Utils) now suggest you use classes instead of singletons, so you can instantiate stores per request.

There are still the following problems that you need to solve in Flux (either yourself or with the help of your favorite Flux library such as Flummox or Alt):

  • If stores are classes, how do I create and destroy them with dispatcher per request? When do I register stores?
  • How do I hydrate the data from the stores and later rehydrate it on the client? Do I need to implement special methods for this?

Admittedly Flux frameworks (not vanilla Flux) have solutions to these problems, but I find them overcomplicated. For example, Flummox asks you to implement serialize() and deserialize() in your stores. Alt solves this nicer by providing takeSnapshot() that automatically serializes your state in a JSON tree.

Redux just goes further: since there is just a single store (managed by many reducers), you don't need any special API to manage the (re)hydration. You don't need to “flush” or “hydrate” stores—there's just a single store, and you can read its current state, or create a new store with a new state. Each request gets a separate store instance. Read more about server rendering with Redux.

Again, this is a case of something possible both in Flux and Redux, but Flux libraries solve this problem by introducing a ton of API and conventions, and Redux doesn't even have to solve it because it doesn't have that problem in the first place thanks to conceptual simplicity.

Developer Experience

I didn't actually intend Redux to become a popular Flux library—I wrote it as I was working on my ReactEurope talk on hot reloading with time travel. I had one main objective: make it possible to change reducer code on the fly or even “change the past” by crossing out actions, and see the state being recalculated.

I haven't seen a single Flux library that is able to do this. React Hot Loader also doesn't let you do this—in fact it breaks if you edit Flux stores because it doesn't know what to do with them.

When Redux needs to reload the reducer code, it calls replaceReducer(), and the app runs with the new code. In Flux, data and functions are entangled in Flux stores, so you can't “just replace the functions”. Moreover, you'd have to somehow re-register the new versions with the Dispatcher—something Redux doesn't even have.

Ecosystem

Redux has a rich and fast-growing ecosystem. This is because it provides a few extension points such as middleware. It was designed with use cases such as logging, support for Promises, Observables, routing, immutability dev checks, persistence, etc, in mind. Not all of these will turn out to be useful, but it's nice to have access to a set of tools that can be easily combined to work together.

Simplicity

Redux preserves all the benefits of Flux (recording and replaying of actions, unidirectional data flow, dependent mutations) and adds new benefits (easy undo-redo, hot reloading) without introducing Dispatcher and store registration.

Keeping it simple is important because it keeps you sane while you implement higher-level abstractions.

Unlike most Flux libraries, Redux API surface is tiny. If you remove the developer warnings, comments, and sanity checks, it's 99 lines. There is no tricky async code to debug.

You can actually read it and understand all of Redux.


See also my answer on downsides of using Redux compared to Flux.

Original Thread

By anonymous    2017-09-20

Redux is a small library that represents state as (immutable) objects. And new states by passing the current state through pure functions to create an entirely new object/application states.

If your eyes-glazed over there don't worry. To sum up, Redux does not represent changes in your application's state by modifying objects ( as you would with object-oriented paradigms). Instead state changes are represented as the difference between the input object and the output object (var output = reducer(input)). If you mutate either input or output you invalidate the state.

To sum up another way, immutability is a requirement of Redux because Redux represents your application state as "frozen object snapshots". With these discrete snapshots, you can save your state, or reverse state, and generally have more "accounting" for all state changes.

State of your app is only changed by a category of pure functions called reducers. Reducers have 2 important properties:

  1. They never mutate, returning newly built objects: This allows reasoning about input + output without side-effects
  2. Their signature is always function name(state, action) {}, so it makes it easy to compose them:

Assume the state looks like this:

    var theState = {
      _2ndLevel: {
        count: 0
      }
    }

We want to increment the count, so we make these reducers

const INCR_2ND_LEVEL_COUNT = 'incr2NdLevelCount';

function _2ndlevel (state, action) {
    switch (action.type) {
        case INCR_2ND_LEVEL_COUNT:
            var newState = Objectd.assign({}, state);
            newState.count++
            return newState;
        }
    }

function topLevel (state, action) {
    switch (action.type) {
        case INCR_2ND_LEVEL_COUNT:
            return Objectd.assign({}, {_2ndLevel: _2ndlevel(state._2ndlevel)});
    }
}

Note the use of Objectd.assign({}, ...) to create an entirely new objects in each reducer:

Assuming we have wired up Redux to these reducers, then if we use Redux's event system to trigger a state change ...

    dispatch({type: INCR_2ND_LEVEL_COUNT})

...Redux will call:

    theNewState = topLevel(theState, action);

NOTE: action is from dispatch()

Now theNewState is an entirely new object.

Note: You can enforce immutability with a library (or new language features), or just be careful to not mutate anything :D

For a deeper look, I highly recommend you checkout this video by Dan Abramov (the creator). It should answer any lingering questions you have.

Original Thread

By anonymous    2018-01-29

What you are trying to achieve is Time Travel in Redux, which is one of the core feature provided by Redux.

See this video from Dan https://www.youtube.com/watch?v=xsSnOQynTHs where it is explained.

To implement what you are trying you will need to maintain multiple state in your application.

Lets call them as past, present and future.

  • Past: The application before action 1 is triggered.
  • Present: The current state of application.
  • Future: The future state of application after action 2 is triggered.

So your state will basically look like this:

ApplicationState= {
  past: {},
  present: {},
  future: {},
}

Now, If you want to travel back in time ie equivalent to accessing Past state.

switch(action.type){
  case "ACTIONTYPE_1":
   return {
     ...state,
     past: {...state},
     present: //implemention of logic
   }
}

I found a nice reading on IBM for what you are trying to achieve. Please have a look at it.

Original Thread

Popular Videos 297

Submit Your Video

If you have some great dev videos to share, please fill out this form.