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.
- I didn’t accept the initialState
- 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…