惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
V2EX
C
Check Point Blog
博客园 - Franky
月光博客
月光博客
T
Tenable Blog
博客园 - 聂微东
Cyberwarzone
Cyberwarzone
The GitHub Blog
The GitHub Blog
C
CERT Recently Published Vulnerability Notes
Scott Helme
Scott Helme
IT之家
IT之家
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
C
CXSECURITY Database RSS Feed - CXSecurity.com
F
Full Disclosure
博客园 - 司徒正美
Project Zero
Project Zero
Y
Y Combinator Blog
A
Arctic Wolf
美团技术团队
博客园 - 叶小钗
S
Securelist
F
Fortinet All Blogs
T
Threatpost
T
Threat Research - Cisco Blogs
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
酷 壳 – CoolShell
酷 壳 – CoolShell
MyScale Blog
MyScale Blog
大猫的无限游戏
大猫的无限游戏
Recorded Future
Recorded Future
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
S
Schneier on Security
Apple Machine Learning Research
Apple Machine Learning Research
L
LangChain Blog
P
Privacy International News Feed
博客园_首页
S
SegmentFault 最新的问题
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
腾讯CDC
P
Proofpoint News Feed
Cisco Talos Blog
Cisco Talos Blog
AWS News Blog
AWS News Blog
阮一峰的网络日志
阮一峰的网络日志
G
Google Developers Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Simon Willison's Weblog
Simon Willison's Weblog
雷峰网
雷峰网
P
Proofpoint News Feed
Latest news
Latest news
G
GRAHAM CLULEY

Minko Gechev's blog

skillgrade Unit Tests for AI Agent Skills You Should Care About AI Generative Development LLM-first Web Framework Reactive framework in ~200 lines of JavaScript Managing Angular Are LLMs going to replace us? Prefetching Heuristics Design Patterns in Open Source Projects - Part II Design Patterns in Open Source Projects - Part I What I learned doing 125 public talks - Part I Dynamic imports solve all the problems, right? 5 Angular CLI Features You Didn't Know About Angular quicklink Preloading Strategy Introducing Bazel Schematics for Angular CLI Building TypeScript Projects with Bazel Joining Google Playing Mortal Kombat with TensorFlow.js. Transfer learning and data augmentation Fast, extensible, configurable, and beautiful linter for Go Introducing Guess.js - a toolkit for enabling data-driven user-experiences on the Web Machine Learning-Driven Bundling. The Future of JavaScript Tooling. JavaScript Decorators for Declarative and Readable Code 3 Tricks For Using Redux and Immutable.js with TypeScript Follow Your Dream Career with Open Source. Personal Story. Redux Anti-Patterns - Part 1. State Management. Faster Angular Applications - Understanding Differs. Developing a Custom IterableDiffer Faster Angular Applications - Part 2. Pure Pipes, Pure Functions and Memoization Faster Angular Applications - Part 1. On Push Change Detection and Immutability Understanding Dynamic Scoping and TemplateRef Implementing a Simple Compiler on 25 Lines of JavaScript Developing Statically Typed Programming Language WebVR for a Gamified IDE 7 Angular Tools That You Should Consider Announcing ngrev - Reverse Engineering Tool for Angular Implementing Angular's Dependency Injection in React. Understanding Element Injectors. Distributing an Angular Library - The Brief Guide Angular in Production Ahead-of-Time Compilation in Angular 2.5X Smaller Angular 2 Applications with Google Closure Compiler Using Stripe with Angular (Deprecated) Building an Angular Application for Production Implementing the Missing "resolve" Feature of the Angular 2 Router Scalable Single-Page Application Architecture Managing ambient type definitions and dealing with the "Duplicate identifier" TypeScript error Static Code Analysis of Angular 2 and TypeScript Projects Enforcing Best Practices with Static Code Analysis of Angular 2 Projects ViewChildren and ContentChildren in Angular Dynamically Configuring the Angular's Router Angular 2 Hot Loader Lazy Loading of Route Components in Angular 2 Aspect-Oriented Programming in JavaScript Flux in Depth. Store and Network Communication. Using JSX with TypeScript Flux in Depth. Overview and Components. Even Faster AngularJS Data Structures Boost the Performance of an AngularJS Application Using Immutable Data - Part 2 Angular2 - First Impressions Build Your own Simplified AngularJS in 200 Lines of JavaScript Boost the Performance of an AngularJS Application Using Immutable Data Processing Binary Protocols with Client-Side JavaScript Stream your Desktop to HTML5 Video Element Multi-User Video Conference with WebRTC Asynchronous calls with ES6 generators Binary Tree iterator with ES6 generators WebRTC chat with React.js AngularJS in Patterns (Part 3) AngularJS in Patterns (Part 2). Services. Using GitHub Pages with Jekyll! AngularJS in Patterns (Part 1). Overview of AngularJS Singleton in JavaScript Express over HTTPS What I get from the JavaScript MV* frameworks Remote Desktop Client with AngularJS and Yeoman The magic of $resource (or simply a client-side Active Record) AngularJS Inheritance Patterns AngularAOP v0.1.0 Advanced JavaScript at Sofia University AngularJS style guide Lazy prefetching of AngularJS partials VNC client on 200 lines of JavaScript Aspect-Oriented Programming with AngularJS CSS3 flipping effect Practical programming with JavaScript Why I should use publish/subscribe in JavaScript JavaScript, the weird parts Functional programming with JavaScript plainvm Looking for performance? Probably you should NOT use [].sort (V8) JavaScript image scaling ELang Caching CSS with localStorage Self-invoking functions in JavaScript (or Immediately Invoked Function Expressions) Asus N56VZ + Ubuntu 12.04 (en) Asus N56VZ + Ubuntu 12.04 Debian Squeeze + LXDE on Google Nexus S (or having some fun while suffering) HTML5 image editor Курсови проекти – ФМИ Carousel Gallery SofiaJS...
Persistent State of ReactJS Component
2015-03-05 · via Minko Gechev's blog

ReactJS is a framework, by facebook, which adds some well known concepts into the UI development. Each UI could be represented as a state machine but when the state of this state machine could be changed from a lot of places everything gets quite messy, complex and buggy. Given view may be rendered differently with the same model passed as parameter if it depends on some global data. A properly implemented ReactJS component, will be rendered the same way when the same “input parameters” are passed to it. This is based on the well known idea of the pure functions (to be more precise the idea is similar but not the same, because each component may have its own state, which can change).

The code from this article could be found at GitHub.

State

Each ReactJS component may have a state. It also accepts properties passed by its ancestors. Based on the state of the component and the properties passed by its ancestors the component knows how to render itself. For example:

var Ticker = React.createClass({
  componentDidMount: function () {
    var self = this;
    setInterval(function () {
      self.setState({
        ticks: self.state.ticks + 1
      });
    }, 1000);
  },
  getInitialState: function () {
    return { ticks: 0 };
  },
  render: function () {
    return (
      <span>{this.state.ticks}</span>
    );
  }
});

The Ticker has a state, which represents the number of ticks passed. The ticks count is being incremented each second and rendered into a span element. If we want to use this component somewhere onto the page we can:

React.render(<Ticker></Ticker>, document.getElementById('container'));

The snippet above will render the component in a container with id container. Once the Ticker has been rendered the ticking will begin.

Another example for component state could be the position (left and top) of a dialog on the screen, boolean flag, which indicates whether given dialog is open or closed, etc.

Persistence

The state of each component is a JavaScript object, which is stored into the main memory. This means that each component’s state may mutate until page refresh/close of the browser. After that, on page load the component will be initialized with its initial state (in our Ticker example this state will be { ticks: 0 }).

But what if we want our Ticker to keep ticking from the same value, which it reached before the page refresh? Or if we want the dialog to remain on the same page position as it was before the page was closed?

We have one “correct” way to do this - we can use the Flux architecture and save each component’s state into a Store. We can then save the Store’s value into a persistent storage. So now, on each mousemove event we are going to go through the whole flux process of saving data…We can do better by saving the data on specific events, for example in our drag & drop case we can save the dialog’s position on mouseup.

But do we have to create a new database entry for each drop of the dialog? Isn’t it much more suitable to keep this state object into cookies or localStorage? Yes, it is! So now we should have two types of stores:

  • Persistent Stores
  • Cookie/Local storage Stores

Doesn’t it gets a bit messy? There is easier way of doing this which doesn’t violates the component’s “pureness” that much.

What we can do is:

var Ticker = React.createClass({
  getInitialState: function () {
    return JSON.parse(localStorage.getItem('ticker') || '{}');
  },
  componentDidMount: function () {
    var self = this;
    setInterval(function () {
      this.setState({
        ticks: this.state.ticks + 1
      });
      localStorage.setItem('ticker', JSON.stringify(this.state));
    }, 1000);
  },
  render: function () {
    return (
      <span>{this.state.ticks}</span>
    );
  }
});

Okay, this seems to work but we should duplicate the same code for each new element, which state we want to save…There are also some issues with the “transactional” behavior. What if the localStorage is full and it throws an error? We won’t have the state saved persistently so we will have inconsistency between the state in the RAM memory and the one on the disk

Mixins

ReactJS uses one more well known idea for code reuse called mixin. The mixin is basically a piece of code, which provides functionality and could be plugged into a component (class, package, component, whatever…). This is something in-between inheritance and delegation. We can’t state that component using given mixin is a subclass of the mixin but it can be considered as subtype of it, since it implements it’s interface (we can think of duck typing here - “When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck.”). Mixins are usually used in dynamically typed languages such as JavaScript, Ruby, Perl but can also be useful in statically typed languages as well (for example Java, where we implement the mixins as abstract classes or interfaces in Java 8).

So we can implement the localStorage.setItem and localStorage.getItem thing into a mixin. But we won’t have a big value by this…What about if we want to have different types of persistent storages? We want to dynamically change the storage from cookies to localStorage or why not even a RESTful API? If we want to make RESTful calls we need to better have asynchronous API, although localStorage accesses the disk synchronously. So obviously we need an adapter.

react-pstate

A few days ago I wrote the react-pstate mixin, which does exactly this - it allows persistence of the state of ReactJS components, through pluggable storage. For example lets take a look at the following example:

var Ticker = React.createClass({
  mixins: [ReactPersistentState],
  getInitialState: function () {
    return { ticks: 0 };
  },
  componentDidMount: function () {
    this.setPStorage(this.localStorage);
    this.setPId('ticker');
    this.restorePState();
    var self = this;
    setInterval(function () {
      this.setPState({
        ticks: this.state.ticks + 1
      });
    }, 1000);
  },
  render: function () {
    return (
      <span>{this.state.ticks}</span>
    );
  }
});

This code looks a little bit simpler. We don’t use any globals but only instance methods instead. The magic happens in these three lines of code:

this.setPStorage(this.localStorage);
this.setPId('ticker');
this.restorePState();

Initially we set the persistent storage we are going to use by this.setPState(this.localStorage), later we set a unique identifier of the component this.setPId('ticker') and after that we restore the component’s state if there is such by calling this.restorePState.

In order to save the component’s state persistently you can use this.setPState, which has exactly the same interface as this.setState, as first argument it accepts the new state and as second a callback, which will be invoked once the state is set.

But how to change the storage from localStorage to XHR for example? We simply need to pass to setPStorage an object, which implements the following interface:

  • get(id) : Promise
  • set(id, state) : Promise
  • remove(id) : Promise

Since we want to have standardized interface for each storage and having asynchronous APIs of the stores, each of these methods should return an ECMAScript 6 promise object. Since not all browsers support it you can use the polyfill by Jake Archibald.

You can find this module at my GitHub account.

Conclusion

The mixin seems quite useful. However, it doesn’t solve all the problems you might have for persistently storing the state of a component. For example saving the state of a dialog on mousemove, isn’t the best thing you can do. This will lead to disk access/HTTP request each few milliseconds. In this case a better way of using react-pstate is by saving it on drag stop. However, it provides you primitives which prevent having code duplication.