This paper is part of my preparation of documents related to Rdeco. Actually, I have been struggling with the meaning of this library, which does not refer to the value of the library itself, but the positioning of this library. The earliest positioning of this library was just to get rid of the heavy state management ecology in the React complex mode. At first, it only encapsulated the capabilities of useReducer, and its prototype was structure-React-Hook. If you read my article a few months ago, you may have some impressions. However, as time goes by, I find more and more that the capabilities of this library have already exceeded the initial expectations. After joining Rx.js, I realized that this could be a whole new programming paradigm. I personally use different programming paradigms like functional, OOP, AOP, and so on. Rx. js promotes responsiveness as a very beneficial programming paradigm, but because rx.js’s responsiveness is based on function, and function is a very obscure but very clever way to mathematically model real-world processes, It was also hard to master, so I eventually redesigned the rdeco library to incorporate rx.js responses into normal objects, and that’s where the reactive object thing came in.

Reactive objects and plain objects

Ordinary objects

const helloWorld = {
  text: 'hello world'.print() {
    console.log(this.text); }};const code = {
  type: 'javascript'.getType() {
    console.log(this.type); }};Copy the code

The characteristic of ordinary objects is that their abstractions are cohesive, and inside them you can create properties and methods that mimic other things in the real world. However, there is communication between things in the real world, which may be one-way or two-way, while ordinary objects do not have the ability to communicate. When two objects need to communicate, they often need to establish a dependency relationship, which can be implemented in the same environment. Like the example above

code.callHelloWroldPrint = () = > {
  helloWorld.print();
};
Copy the code

To tell the helloWorld object to execute the print method, the code object needs to get the instance of the helloWorld object and operate on it directly. This dependency forces objects to form a network of relationships. Moreover, the network relationship is indivisible and cannot be divided by time and space, which makes it difficult for modeling methods based on common objects to truly abstract the real world.

Because although the relationship between objects in the real world is also a mesh relationship, our mesh relationship can be divided into different time and space, which makes the interaction between objects less emphasis on the consistency of time and space.

To take the simplest example, you can tell your friend to go to an event on a certain day. You don’t need to call your friend over and tell him or her to do so because we have all kinds of communication tools (phone, mail…). And correspondence identification (home address, name, address, zip code…)

Programming is essentially the process of virtualizing the real world, and in order to do that, we need a way to simulate this communication mechanism in the real world so that ordinary objects can interoperate in different time and space.

And that’s what @rdeco/core is all about.

Rdeco adds a more responsive mechanism to ordinary objects than subscribing to publish, allowing them to interoperate at different times and Spaces.

Responsive object

Let’s create two objects that are distributed in different Spaces and loaded at different times. Usually, different Spaces mean publishing to different resource servers. For example, we publish Jacky objects to CDn.a /jacky.js

import { create } from 'rdeco';

create({
  name: 'jacky'.state: {
    age: 19,},exports: {
    setAge(newAge) {
      this.controller.setAge(newAge);
    },
    getAge(next) {
      next(this.state.age); }},controller: {
    setAge() {
      this.setter.age(20); ,}}});Copy the code

The Jacky object exposes two methods that other objects can call and sets its age from 19 to 20 when calling printAge.

Then we create another object Ann and publish it to cdn.b/ann.js

import { create, inject } from 'rdeco';

create({
  name: 'ann'.subscribe: {
    jacky: {
      state: {
        age({ nextState }) {
          console.log(nextState); }},}},controller: {
    onStart() {
      inject('jacky')
        .getAge()
        .then((age) = > {
          inject('jacky').setAge(age + 1); }); ,}}});Copy the code

When the object Ann is initialized, the getAge method of the Jacky object is called to obtain the age of the current Jacky. Meanwhile, after + 1, the setAge method of the Jacky is called to update the age of the Jacky, which is analogous to the model of the real world.

Ann: How old is Jacky? Jacky: 19. Ann: You'd have to be 20

If the event happens in the same space and time, such as Ann and Jacky meeting face to face one afternoon for a casual chat, then you can abstract the process by using ordinary objects. But if Ann and Jacky are from two different countries and their time zones are different, Ann sends a message to Jacky in the morning, and Jacky is still sleeping, and Ann goes to sleep again when Jacky replies. This process cannot be abstracted by ordinary objects because the space and time are different.

On the flip side, this inseparability of time and space also results in front-end JavaScript code piling up rather than splitting. Because of the module we wrote, packages in NPM must be downloaded locally and run at the same time and in space to interoperate properly.

Only a few environmental-level modules can be placed on a CDN to break the spatial dependency, but even so, you can’t run react. CreateElement before React loads. It’s still a time dependence.

Rdeco has a set of apis that allow interaction of responsive objects across time and space. The following is probably too well documented, but since you’ve never seen it, I don’t think it’s too boring.

API

Reactive objects contain a set of interoperable apis that allow you to allow two reactive objects to interoperate independently of time and space

exports

Exports is used to expose methods that can be called after inject.

inject('mdoule-a').foo();

create({
  name: 'module-a'.exports: {
    foo() {
      console.log('foo'); ,}}});// log foo
Copy the code

Return the result of the call through next

If you need to pass some value to the caller in an exports exposed method, you can use next, which is present in all exports exposed methods

inject('mdoule-a')
  .foo()
  .then((foo) = > {
    console.log(foo);
  });

create({
  name: 'module-a'.exports: {
    foo(next) {
      next('foo'); ,}}});// log foo
Copy the code

inject

Inject is used to send instructions to the target module. This process does not require the target module to be actually ready, just like when you write a letter to the target, you do not need to know whether the target is at home.

  • inject([moduleName]) => exports

subscribe

Subscribe is used in response to a sequence of operations on the target object

  • subscribe.state[key]({nextState, prevState, state})
create({
  name: 'foo'.subscribe: {
    bar: {
      state: {
        name({ nextState }) {
          console.log(nextState); },},},},});const bar = create({
  name: 'bar'.state: {
    name: null,},controller: {
    onNameSet(name) {
      this.setter.name(name); ,}}}); bar.controller.onNameSet('foo');

//console.log foo
Copy the code
  • subscribe.eventkey

The Event and emit APIS are a set of relational apis that allow a target object to emit so that other objects can respond to the corresponding event function

create({
  name: 'foo'.subscribe: {
    event: {
      nameSetOver(name) {
        console.log(`hello ${name}`); }},}});const bar = craete({
  name: 'bar'.state: {
    name: null,},controller: {
    onStart() {
      this.setter.name('bar');
      this.emit('nameSetOver'.'bar'); ,}}}); bar.conroller.onStart();// console.log hello bar
Copy the code
  • subscirbe.controllerkey
  • subscirbe.servicekey

Controller and Service are just a quick syntax for a set of events to avoid you declaring too many similar emit event functions

Why can’t event use Next to return a value?

Subscribe, unlike exports, is essentially a broadcast mode, and providing the next return value can lead to some unexpected situations. So if you need to return the result to the calling object after responding to the event, you should go through the exports exposed method. It might be a little tricky, but for communications across time and space, accuracy and control of the flow of traffic are more important

Finally, if you are interested in responsive objects, or rx.js you can follow our project github.com/kinop112365…