Student: Fong, the interviewer asked me to write the Redux by hand

Fang: Let you dictate Redux over the phone?

Student: It’s an offline interview, give me a computer and ask me if I can write. I can’t write it. It’s embarrassing

Fang: How much does this position pay? Dare to ask such a hard question

Student: 20 ~ 30 k k

That’s reasonable

Student: Well, I guess I’m not worth that much

Fang: Don’t lose heart. Actually, it’s very simple. You will be able to write after I tell you once

Student: Really? You talk about bai

If you want to understand a library, it is best to write a similar library yourself and compare your code with its code.

Student: I can’t write it myself…

Fang: You should first ask yourself, what is the problem Redux is trying to solve

Predictable State Container for JavaScript apps While shopping at the Predictable state container for JavaScript apps

Fang: That’s right. Redux says it’s a predictable container of state.

Student: No…

Fang: Never mind, let’s start with “state”. I’ll build a library from scratch and gradually show you how to optimize:

App has three sons, and one AppState, and now we want to share the AppState with all the User components in the eldest, so it’s easy to think of using Context, right

Want to display appstate.user.name in the User component of the eldest child

Student: Well, you need to wrap the whole App with the Provider first

Add three lines of code, like this:

Then go to the User component of the older child and use Consumer:

Student: Is it still possible to use useContext?

Fang: Well, useContext is a little more concise:

Student: I like useContext

Fang: Now, we seem to have solved the appState sharing problem, right? So how do you update appState?

Student: I see you put setAppState in contextValue as well, just use it, right?

I added a UserModifier component in my second son, which included an input modifier to modify appState.user.name

Student: I don’t think you can change user.name with this code

Fang: Why?

Student: Because the object you passed to setAppState is the same object, even though you changed the name inside, the object reference is the same

Fang: Yes, you are right, so I will create a new object:

Running successfully:

Student: Wait, there is something wrong with codes 56 ~ 58:

const onChange = (e) => { const { appState, setAppState } = contextValue; appState.user.name = e.target.value; setAppState({ ... appState }); };Copy the code

You actually changed the appState and then used {… AppState} to create a new object

Fang: Isn’t that ok? You can see the code still works.

Student: I can’t say what the problem is, but it’s not recommended.

How about this: We encapsulate the process of creating a new state into a function createNewState(), and the user can get the new state simply by passing in an argument: createNewState()

Student: Right, so developers would have to change the source code of createNewState if they wanted to mess with it.

Fang: To prevent new hires from being understaffed, we put createNewState in a separate file:

Student: This function looks familiar to me. Is this reducer?

Party: Yes, there are only two differences between our reducer and createNewState.

  1. I didn’t accept the initialState
  2. I didn’t combine actionType and actionData into an action object

Also, the code to create a new object here is tedious, and if I were optimizing it I would probably introduce immer.js, but since Redux isn’t optimizing it, we’ll leave it alone.

Let’s get the action object out first:

Therefore, all calls to createNewState should also be of the form {type, payload} :

Student: The original reducer and action were created to unify and standardize the new state process

Fang:

Student: What about dispatch?

Don’t worry, let’s simplify the above code:

Student: You’re just merging two lines of code into one

F: Look at line 59 setAppState(createNewState(appState,.. This code

Student: What’s wrong with the code

Fang: This code will be repeated countless times in the future

Student: What do you mean?

Now modify user.name to write

setAppState(createNewState(appState, {
  type: "updateUser",
  payload: {
    name: e.target.value
  }
}));
Copy the code

The next time you modify user.age is not to write

setAppState(createNewState(appState, {
  type: "updateUser",
  payload: {
    age: e.target.value
  }
}));
Copy the code

Next time you modify group. Name, do you need to write it

setAppState(createNewState(appState, {
  type: "updateGroup",
  payload: {
    name: e.target.value
  }
}));
Copy the code

Student: Yeah…

SetAppState (createNewState(appState,… Encapsulate it like this:

Student: Yeah, that’s a lot easier. Dispatch is designed to simplify and unify the setState process

Fang: Yes, yes, there is an obvious problem with this code

Student: What is it?

UpdateState can’t read the context, so it can’t access appState and setAppState!

Student: Exactly! So what?

Fang: There are two ways:

  • One is don’t put appState and setAppState in the Context;
  • Two, put updateState in the component, because the component can read the context;

Let me start with the second method. The first one is a little bit different, so I’ll talk about it tomorrow.

Student: The second way is to put updateState in the component, but how

Fong: The language is hard to describe, let’s just look at the code. First, we’ll prepare an empty component that passes appState and setAppState to updateState() :

The Wrapper component then passes the updateState to the UserModifier and renders the UserModifier:

The UserModifier component then gets “updateState, which accesses the Context” from props:

Student: Should I use the Wrapper component instead of the UserModifier component?

Fang: Well, change the UserModifier component in the second son to the Wrapper component.

Student: Let me see, you intentionally created an empty component Wrapper so that updateState could access the Context, and then rendered the UserModifier to the Wrapper

Fang: that’s right

Student: I see. But there’s a problem. Wouldn’t I have to put a Wrapper around each component to get “updateState with Context access”?

Fang: that’s right

Student: Surely you have some way of eliminating repetition?

Of course, we could write a createWrapper function:

Then rewrite UserModifier directly to createWrapepr as UserModifier:

Thus, the UserModifier is the original Wrapper, use the UserModifier component directly:

Finally, this createWrapper can be extracted into a separate file.

Student: The createWrapper function looks like connect

Fang: Yes, it is connect. Let’s refactor it and rename it to Connect:

Student: Could the update Estate be renamed Dispatch as well

Can be changed:

Student: Ah, more and more like Redux. Dispatch, can you still accept state

Fang: Of course, just inject appState when CONNECT is injected into Dispatch

The User component does not need to fetch the User from Conext itself, and can inject state directly by connecting:

Student: Connect is really convenient. Is this the higher-order component of legend?

Fang: Yeah, there’s nothing complicated about these terms. It’s easy to understand them from zero

Student: Well, I see that Redux provides connect that accepts two parameters:

connect(mapState, mapDispatch)(Counter)
Copy the code

How do you do that?

Fang: These are just tips. I’ll talk about them tomorrow. That’s all for today. I will send you the current code, you can run to see if there is any problem.

Student: Ok, I’ll try it myself first.

Subsequent juejin. Cn/post / 694268…