Redux introduces

Ruan Yifeng teacher’s literacy

  • state

    The entire redux data is stored in the store, and state is a snapshot of the store at some point in time.

    store.getState()

  • action

    The state can be changed, and an action is an object that the view notifies (or merely notifies, or carries partial information with it)

    Type: 'ADD_TODO', // Payload: 'Learn redux '};Copy the code

View emits action: store.dispatch(action)

  • reducer

    Replace the received action with the old state with the new state.

    Ruan Yifeng teacher:

    Because Reducer is a pure function, the same State can be guaranteed and the same View must be obtained. But because of this, the Reducer function cannot change State and must return a new object

    It is best to make the State object read-only. You can’t change it, the only way to get a new State is to generate a new object. The advantage of this is that at any time, the State corresponding to a View is always a constant object.

  • subscribe

    Question: A view sends an action to change the state of the view.

    Answer: View makes the subscription: Store. Subscribe

    See Teacher Ruan Yifeng’s explanation for details

  • Reducer reducer Reducer Reducer Reducer Reducer Reducer Reducer reducer reducer reducer reducer reducer

Redux introduction here is no longer redundant, Ruan Yifeng teacher explained very well, want to see some simplified demo please move reDUx source code, above not only posted all kinds of examples and problems to solve even the heart course, is I have met the most kind of source :book:

Those who want to know the origin of Redux can refer to Flux or github developer profiles, such as this guy acDLite

A confusing point in Redux

Fork source code analysis, here are some questions

build

src/index.ts:

/* * This is a dummy function to check if the function name has been altered by minification. * If the function has been  minified and NODE_ENV ! == 'production', warn the user. */
function isCrushed() {}

if( process.env.NODE_ENV ! = ='production' &&
  typeof isCrushed.name === 'string'&& isCrushed.name ! = ='isCrushed'
) {
  warning(
    'You are currently using minified code outside of NODE_ENV === "production". ' +
      'This means that you are running a slower development build of Redux. ' +
      'You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify ' +
      'or setting mode to production in webpack (https://webpack.js.org/configuration/mode/) ' +
      'to ensure you have the correct code for your production build.')}Copy the code

This is the first file I saw in Redux, I was shocked at first glance, declared an empty function isCrushed, and then used the function name to check??

The good news is that it’s just warning:dog:, and the file has comments and warnings in it, basically warning when the code is compressed or not in production. The function name can be used to check if the code has been compressed. The details can be tweaked using Webpack. Webpack 4 now compresses JS by default.

I’m personally curious about the origin of isCrushed. Name

Each Function is an instance of Function (emM)

  • Arguments, an array object that contains arguments passed in. Arrow functions have no arguments (but I use Node to run arguments). I don’t know what the output is either.)
  • Caller, if a functionfIs called in global scope, thenf.callerfornullIf, on the other hand, a function is called within the scope of another functionf.callerRefers to the function calling it. (MDN)
  • Length, the number of named arguments the function wants to accept (little Red Book P116),?? Js does not check parameters
  • Name, the function name
  • I’ll skip the prototype chain and scope
  • [[FunctionLocation]]: vm53:1, EMM, in my current eyes, what JS engine, virtual machine, runtime environment togetherThe environmentI wonder if there will ever be a day to correct my misconceptions

overload

src/applyMiddleware.ts

import ... /** *... Export default function applyMiddleware(): StoreEnhancer export default function applyMiddleware<Ext1, S>( middleware1: Middleware<Ext1, S, any> ): StoreEnhancer<{ dispatch: Ext1 }> export default function applyMiddleware<Ext1, Ext2, S>( middleware1: Middleware<Ext1, S, any>, middleware2: Middleware<Ext2, S, any> ): StoreEnhancer<{ dispatch: Ext1 & Ext2 }> export default function applyMiddleware<Ext1, Ext2, Ext3, S>( middleware1: Middleware<Ext1, S, any>, middleware2: Middleware<Ext2, S, any>, middleware3: Middleware<Ext3, S, any> ): StoreEnhancer<{ dispatch: Ext1 & Ext2 & Ext3 }> export default function applyMiddleware<Ext1, Ext2, Ext3, Ext4, S>( middleware1: Middleware<Ext1, S, any>, middleware2: Middleware<Ext2, S, any>, middleware3: Middleware<Ext3, S, any>, middleware4: Middleware<Ext4, S, any> ): StoreEnhancer<{ dispatch: Ext1 & Ext2 & Ext3 & Ext4 }> export default function applyMiddleware<Ext1, Ext2, Ext3, Ext4, Ext5, S>( middleware1: Middleware<Ext1, S, any>, middleware2: Middleware<Ext2, S, any>, middleware3: Middleware<Ext3, S, any>, middleware4: Middleware<Ext4, S, any>, middleware5: Middleware<Ext5, S, any> ): StoreEnhancer<{ dispatch: Ext1 & Ext2 & Ext3 & Ext4 & Ext5 }> export default function applyMiddleware<Ext, S = any>( ... middlewares: Middleware<any, S, any>[] ): StoreEnhancer<{ dispatch: Ext }> export default function applyMiddleware( ... middlewares: Middleware[] ): StoreEnhancer<any> { ... Omit internal logic}Copy the code

I didn’t know ts had function overloads and I was scared again

Question: Why did JS not overload?

Answer:

1. Dynamic language, function parameters are put in the class array object, do not define the parameter type, also do not check the type and number of parameters

2. Js function is also an object, the so-called function signature is a pointer, not bound to a specific function (see the little Red Book P110 for details).

I feel this problem is super broad and deep. I will come back to fight the war after ten years of training

The typescript overload 🌰 :

function test(arg:number):string;
function test(arg:string):number;
function test(arg:any):any {
  if(typeof arg === 'number') {
    return 's';
  }
  if(typeof arg === 'string') {
    return 0;
  }
}

console.log(test(99))     // s
console.log(test('123'))  // 0
Copy the code

Ts supports function overloading, although it is awkward to use

TypeScript overloads by taking the parameters passed in and matching them down the signature list of overloaded methods, matching what, the type and number of arguments. An error is reported until a matching function signature is found.

So the recommended approach is to put a more signature specific overload at the top and a less specific overload at the end where the last signature contains all the previous signatures, and it’s not in the overload list

Why do they do that? Anyway, I don’t want to delve into the design principles of TS. It generally works, but typeof is weak, and redux is full of generics, so from my starting point, it still doesn’t work

Question: Why does applyMiddleware use parameters 1 to 5?

(I don’t know, deleted did not run the test, :cry:)

chain

src/compose.ts

The sequential chain calls to functions that are at the heart of Applymiddleware above

export default function compose(... funcs: Function[]) { if (funcs.length === 0) { // infer the argument type so it is usable in inference down the line return <T>(arg: T) => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (... args: any) => a(b(... args))) }Copy the code

Damn elegant :love_letter:, after reading it, I can’t help writing a reduce, I don’t know where the test can run :confused:

toString

src/utils/actionTypes.ts

const randomString = () =>
  Math.random().toString(36).substring(7).split('').join('.')
Copy the code

The document amounted to only a few dozen lines. What I care about is the toString method

Js toString generally refers to the Object. The prototype. The toString (), with no arguments, but the Number to rewrite it, radix can take parameters, the range 2-36, specify the transformation goal into the system, raise RangeError overspray.

Question: Does the toString of Number default the Number to be converted to decimal, or is it automatically recognized? I don’t know. Look at an example

console.log((6).toString(2)); // Output '110', base 2 of 6 110 console.log((254).tostring (16)); // Output 'fe', 254 hexadecimal fe console.log((-10).tostring (2)); Console. log((-0xff).toString(2)); / / output '11111111'Copy the code

The above example is from MDN, feel a little loophole ah, to a hexadecimal, try others, are considered as decimal

plainObject

src/utils/isPlainObject.ts

export default function isPlainObject(obj: any): boolean { if (typeof obj ! == 'object' || obj === null) return false let proto = obj while (Object.getPrototypeOf(proto) ! == null) { proto = Object.getPrototypeOf(proto) } return Object.getPrototypeOf(obj) === proto }Copy the code

A function to determine whether an argument is a plainObject, with few lines of code.

Question:plainObject?

At first I didn’t know what plainObject was, and after reading a bunch of fancy explanations, I’d rather look at the implementation of Redux and Lodash:

lodash:

function isPlainObject(value) { if (! isObjectLike(value) || getTag(value) ! = '[object Object]') { return false } if (Object.getPrototypeOf(value) === null) { return true } let proto = value while  (Object.getPrototypeOf(proto) ! == null) { proto = Object.getPrototypeOf(proto) } return Object.getPrototypeOf(value) === proto }Copy the code

Just to make it easier

Emm, code tells me everything, top of the prototype chain

Var x = new Fruite() or object.create (); var x = new Fruite();

Question: Better?

Discussion on Stack Overflow

The following

const failIsPlainObject_1 = (obj: any) => {
  return Object.getPrototypeOf(obj) === Object.prototype;
}
Copy the code

It failed. It didn’t pass the test. Object. Prototype may have multiple arrays in cross-realm and cross-iframe cases

const myIsPlainObject = (obj: any) => {
 let proto = Object.getPrototypeOf(obj)
 return Object.getPrototypeOf(proto) === null
}
Copy the code

After successfully running the test,

Question: Why not?

See the link above, see the discussion, because while actually goes back to the vertex, this method might find a subclass

By the way, the Object. The prototype. ToString. Call 🐂 🍺

observable

src/utils/symbol-observable.ts

declare global {
  interface SymbolConstructor {
    readonly observable: symbol
  }
}

const $$observable = /* #__PURE__ */ (() =>
  (typeof Symbol === 'function' && Symbol.observable) || '@@observable')()

export default $$observable
Copy the code

Can be divided into two sections, the first paragraph is a knowledge point, at least seen, the second paragraph is a little meng

Ts :Global Modifing Module

Similar questions:

  • @types

Paragraph 2, Question:

  • Execute the function immediately?
  • Symbol.observableand@@observableWhat does it mean?

See_no_evil: