The more we are accustomed to things, may often contain great philosophy, the more simple things, may often contain great wisdom.
Today we will talk about the von Neumann system that supports the entire computer virtual world, supports the entire Internet, and supports the foundation of the Internet Tech Giants we are familiar with, such as Tencent, Alibaba, Microsoft, and Google.
Let’s see how simple it is, but how great it is at the same time, and feel the philosophy together.
That is to say, in fact, the so-called JSX needs to be compiled to generate React code, which is somewhat similar to Vue’s template. Vue’s template will also be compiled to generate a render function. In this function, for each tag, it will call its own API to create vnode.
Specify
The first part of the JSX tag specifies the type of the React element.
JSX tags that start with a capital letter mean they are React components. These tags are compiled as direct references to named variables, so when you use JSX < Foo/> expressions, ‘Foo’ must be included in scope.
React
Since JSX compiles as React.createElement calls, the React library must also be included in the JSX code scope.
For example, in the following code, although’React ‘and’CustomButton’ are not directly used, they still need to be imported:
1 2 3 4 5
import React from 'react';import CustomButton from './CustomButton'; function WarningButton() { // return React.createElement(CustomButton, {color: 'red'}, null); return <CustomButton color="red" />; }
If you load React directly through the < script > tag instead of using a JavaScript packaging tool, you must mount React into a global variable.
In
In JSX, you can also use dot syntax to reference a React component. This is very handy when you export many React components in a module. For example, if’MyComponents. DatePicker 'is a component, you can use it directly in JSX:
1 2 3 4 5 6 7 8 9 10 11
import React from 'react';
const MyComponents = { DatePicker: function DatePicker(props) { return <div>Imagine a {props.color} datepicker here.</div>; } }
function BlueDatePicker() { return <MyComponents.DatePicker color="blue" />; }
User-defined components must start with a capital letter
Elements starting with a lowercase letter represent an HTML built-in component, such as’ < div > ‘or’ < span > ‘will generate the corresponding string “div” or “span” to be passed to’React.createElement’ (as a parameter). Elements starting with uppercase letters correspond to components introduced or customized in JavaScript, such as’ < Foo/> 'will compile to’React.createElement (Foo) '.
We recommend naming custom components with uppercase letters. If you do need a component that starts with a lowercase letter, you must assign it to a variable that starts with an uppercase letter before using it in JSX.
For example, the following code will not run as expected.
1 2 3 4 5 6 7 8 9 10 11 12
import React from 'react';
//Error! Components should start with a capital letter: function hello(props) { //Correct! This use of < div > is legal because div is a valid HTML tag return <div>Hello {props.toWhat}</div>; }
function HelloWorld() { //Error! React will think < hello/> is an HTML tag because it doesn't start with a capital letter: return <hello toWhat="World" />; }
To fix this, we need to rename hello to Hello and use < Hello/> in JSX:
1 2 3 4 5 6 7 8 9 10 11 12
import React from 'react';
//Correct! Components need to start with a capital letter: function Hello(props) { //Correct! This use of < div > is legal because div is a valid HTML tag: return <div>Hello {props.toWhat}</div>; }
function HelloWorld() { React knows that < Hello/> is a component because it starts with a capital letter: return <Hello toWhat="World" />; }
Select type at runtime
You cannot use a universal expression as a React element type. If you want to (dynamically) determine the element type through a universal expression, you need to first assign it to a variable starting with a capital letter. This is usually used when rendering different components based on prop:
1 2 3 4 5 6 7 8 9 10 11 12
import React from 'react'; import { PhotoStory, VideoStory } from './stories';
function Story(props) { //Correct! JSX types can be variables starting with uppercase letters. const SpecificStory = components[props.storyType]; return <SpecificStory story={props.story} />; }
JSX
There are several ways to specify props in JSX.
JavaScript
You can pass a JavaScript expression wrapped in ‘{}’ as a prop to a JSX element. For example, JSX like this:
1
<MyComponent foo={1 + 2 + 3 + 4} />
In MyComponent, the value of props.foo is equal to the result of 1 + 2 + 3 + 4.
'If ‘statements and’for’ loops are not JavaScript expressions, so they cannot be used directly in JSX. However, you can use them in code other than JSX. For example:
1 2 3 4 5 6 7 8 9
function NumberDescriber(props) { let description; if (props.number % 2 0) { description = <strong>even</strong>; } else { description = <i>odd</i>; } return <div>{props.number} is an {description} number</div>; }
You can learn more about it in the corresponding chapters条件渲染And循环The content.
String literal
You can assign string literals to prop. The following two JSX expressions are equivalent:
1 2 3
<MyComponent message="hello world" />
<MyComponent message={'hello world'} />
When you assign a string literal to a prop, its value is unescaped. Therefore, the following two JSX expressions are equivalent:
1 2 3
<MyComponent message="<3" />
<MyComponent message={'<3'} />
This behavior is usually unimportant, here is just a reminder of this usage.
Props
If you do not assign a value to prop, its default value is’true '. The following two JSX expressions are equivalent:
1 2 3
<MyTextBox autocomplete />
<MyTextBox autocomplete={true} />
Generally, we do not recommend not passing value to prop, as this may be related to ES6 对象简写Confused, ‘{foo}’ is short for ‘{foo: foo}’, not ‘{foo: true}’. This implementation is only to maintain the same behavior as tag attributes in HTML.
Attribute expansion
If you already have a props object, you can use the expansion operator… to pass the entire props object in JSX. The following two components are equivalent:
1 2 3 4 5 6 7 8
function App1() { return <Greeting firstName="Ben" lastName="Hector" />; }
In the above example, the prop of’kind ‘will be safely kept and will * not * be passed to the’ < button > ‘element in the DOM. All other props will be passed through the’… other ‘object, making the application of this component very flexible. You can see that it passes an’onClick’ and’children 'attribute.
Attribute expansion is useful in some cases, but it is also easy to pass unnecessary props to unrelated components or invalid HTML attributes to the DOM. We recommend using this syntax with caution.
JSX
The content of the JSX expression contained between the start and end tags will be passed to the outer component as a specific attribute’props.children '. There are several different ways to pass child elements:
String literal
You can put the string between the start and end tags, where’props.children 'is just the string. This is useful for many built-in HTML elements. For example:
1
<MyComponent>Hello world!</MyComponent>
This is a valid JSX, and the props.children in MyComponent is a simple non-Escape Character string “Hello world!”. So you can write JSX the same way you write HTML. As shown below:
1
<div>This is valid HTML & JSX at the same time.</div>
JSX will remove spaces at the beginning and end of the line as well as blank lines. Empty lines adjacent to the label will be deleted, and new lines between text strings will be compressed into one space. Therefore, the following methods are equivalent:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<div>Hello World</div>
<div> Hello World </div>
<div> Hello World </div>
<div>
Hello World </div>
JSX
Child elements can be composed of multiple JSX elements. This is very useful for nested components.
You can mix different types of child elements together, so you can use string literals with JSX child elements. This is also a manifestation of JSX similar to HTML, so the following code is legal JSX and also legal HTML:
1 2 3 4 5 6 7
<div> Here is a list: <ul> <li>Item 1</li> <li>Item 2</li> </ul> </div>
React components can also return a set of elements stored in an array:
1 2 3 4 5 6 7 8 9
render() { No need to wrap the list elements with additional elements! return [ Don't forget to set the key:) <li key="A">First item</li>, <li key="B">Second item</li>, <li key="C">Third item</li>, ]; }
JavaScript
JavaScript expressions can be wrapped in ‘{}’ as child elements. For example, the following expressions are equivalent:
1 2 3
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent>
This is very useful for displaying lists of arbitrary length. For example, rendering HTML lists:
1 2 3 4 5 6 7 8 9 10 11
function Item(props) { return <li>{props.message}</li>;}
function TodoList() { const todos = ['finish doc', 'submit pr', 'nag dan to review']; return ( <ul> {todos.map((message) => <Item key={message} message={message} />)} </ul> ); }
JavaScript expressions can also be combined with other types of child elements. This approach can conveniently replace template strings.
1 2 3
function Hello(props) { return <div>Hello {props.addressee}!</div>; }
Function as a child element
Usually, JavaScript expressions in JSX will be evaluated as strings, React elements, or lists. However, ‘props.children’, like other props, can pass any type of data, not just the renderable types known to React. For example, if you have a custom component, you can pass the callback function as’props.children ':
1 2 3 4 5 6 7 8 9 10 11 12 13 14
//Call the child element callback numTimes times to repeatedly generate the component function Repeat(props) { let items = []; for (let i = 0; i < props.numTimes; i++) { items.push(props.children(i)); } return <div>{items}</div>; }
function ListOfTenThings() { return ( <Repeat numTimes={10}> {(index) => <div key={index}>This is item {index} in the list</div>} </Repeat> ); }
You can pass anything as a child element to a custom component, just make sure it can be converted into an object that React understands before rendering it. This usage is not common, but can be used to extend JSX.
Boolean type, Null
'False ‘,’ null ‘,’ undefined ‘, and’true’ are valid child elements. But they will not be rendered. The following JSX expressions render the same:
1 2 3 4 5 6 7 8 9 10 11
<div />
<div></div>
<div>{false}</div>
<div>{null}</div>
<div>{undefined}</div>
<div>{true}</div>
This helps to render other React elements based on specific conditions. For example, in the following JSX, the < Header/> component is rendered only when’showHeader ‘is’true’:
It is worth noting that there are some “falsy” 值, like the number ‘0’, will still be rendered by React. For example, the following code will not work as you expect, because ‘0’ will still be rendered when’props.messages’ is an empty array:
Conversely, if you want to render values such as’false ‘,’ true ‘,’ null ‘,’ undefined ', you need to first convert them转换为字符串:
1 2 3
<div> My JavaScript variable is {String(myVariable)}. </div>
Summary
There is nothing to understand in this section, it is all grammatical issues, but there are a few places to pay attention to:
React components must be in scope.
Names of React components must start with uppercase.
The content between component tags will be as prop.children, which can be expressions, functions, strings, etc.
It’s worth noting that there are some “falsy” 值, such as the number ‘0’, will still be rendered by React. For example, the following code will not work as you expect, because ‘0’ will still be rendered when’props.messages’ is an empty array: To solve this problem, make sure that the expression before ‘& &’ is always a boolean value:
In this blog we continue to look at the Context section of the React Advanced Guide.
This will be interspersed with component composition, render prop, and some knowledge of function components.
Why use context?
Context provides a way to pass data between component trees without manually adding props for each layer of components.
In a typical React application, data is passed from top to bottom (by parent and child) through props properties, but this usage is extremely cumbersome for certain types of properties (such as locale preferences, UI themes), these properties are required by many components in the application. Context provides a way to share such values between components without explicitly passing props layer by layer through the component tree.
From my understanding, if a property needs to be shared by multiple components and passed layer by layer, we can use this method.
Why meet these two conditions?
If it is simply common to multiple sibling components, we can use the state promotion method.
If we simply pass it layer by layer, we can also use a combination of components.
When to use
Context is designed to share data that is “global” to a component tree, such as the currently authenticated user, theme, or preferred language. For example, in the following code, we manually adjust the style of a button component through a “theme” attribute:
function Toolbar(props) { //The Toolbar component takes an additional "theme" property and passes it to the ThemedButton component. //If each individual button in the application needs to know the value of theme, this will be a very troublesome thing. Because this value must be passed layer by layer to all components. return ( <div> <ThemedButton theme={props.theme} /> </div> ); }
//Context allows us to pass values deep into the component tree without explicitly passing them through each component. //Create a context for the current theme ("light" is the default). const ThemeContext = React.createContext('light'); class App extends React.Component { render() { //Use a Provider to pass the current theme to the following component tree.//No matter how deep, any component can read this value.//In this example, we pass "dark" as the current value. return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> ); } }
The middle component no longer has to specify the theme to be passed down. function Toolbar() { return ( <div> <ThemedButton /> </div> ); }
class ThemedButton extends React.Component { Specify contextType to read the current theme context. //React will go up to the nearest theme provider and use its value. //In this example, the current theme value is "dark". static contextType = ThemeContext; render() { return <Button theme={this.context} />; } }
Note that in order to use this.context, you must first define static.
For example, ‘static’ in the above example
Use
The main use case for Context is that * many * components at different levels need to access some of the same data. Use caution as this makes components less likely to reuse.
** If you just want to avoid passing some properties layer by layer,组件组合(component composition)Sometimes a better solution than context. **
Component combination
For example, consider a Page component that passes down the user and avatarSize properties so that deeply nested Link and Avatar components can read them:
If in the end only the Avatar component really needs user and avatarSize, then passing these two props layer by layer is very redundant. And once the Avatar component needs more props from the top-level component, you have to add them one by one at the middle level, which will become very troublesome.
A ** no context ** solution is将 Avatar 组件自身传递下去Therefore, the intermediate component does not need to know props such as’user ‘or’avatarSize’.
//Now, we have this component: <Page user={user} avatarSize={avatarSize} /> //... render... <PageLayout userLink={...} /> //... render... <NavigationBar userLink={...} /> //... render... {props.userLink}
With this change, only the topmost Page component needs to know how the Link and Avatar components use user and avatarSize.
This inversion of control over components reduces the number of props to pass in your application, which in many cases will make your code cleaner and give you more control over the root component. However, this doesn’t apply to every scenario: this kind of lifting the logic to a higher level in the component tree will make these high-level components more complex and force low-level components to adapt to such a form, which may not be what you want.
And your component is not limited to receiving a single subcomponent. You may pass multiple subcomponents and even encapsulate multiple separate “slots” for these subcomponents (children),正如这里的文档所列举的
This mode is enough to cover many scenarios where you need to decouple the child component from the directly related parent component. If the child component needs to communicate with the parent component before rendering, you can further use render props。
However, sometimes components at different levels in the component tree need to access the same batch of data. Context allows you to “broadcast” this data to all components in the component tree, and all components can access this data and subsequent data updates. Common scenarios for using context include managing the current locale, theme, or some cached data, which is much simpler than the alternative.
I don’t know if you will be a little confused when you see this doc, let me briefly sort it out:
render
A component with a render prop accepts a function that returns a React element and implements its rendering logic inside the component by calling this function.
Create a Context object. When React renders a component that is subscribed to this Context object, the component will read the current context value from the nearest matching’Provider 'in the component tree.
The defaultValue parameter of the component will only take effect when there is no match to the Provider in the tree where it is located. This default value helps to test the component without wrapping it with a Provider. Note: When passing’undefined ‘to the value of the Provider, the’defaultValue’ of the consuming component will not take effect.
Context.Provider
1
< MyContext. Provider value = {/* some value */} >
Each Context object returns a Provider React component that allows the consuming component to subscribe to changes in the context.
Provider receives a’value 'attribute and passes it to the consumer component. A Provider can have a corresponding relationship with multiple consumer components. Multiple Providers can also be used nested, and the inner layer will overwrite the outer layer of data.
When the provider’s value changes, all consumer components inside it will be re-rendered. Neither the provider nor its internal consumer components are subject to the shouldComponentUpdate function, so consumer components can be updated if their ancestor components exit the update.
To determine the change by detecting the old and new values, the Object.is The same algorithm.
Attention
When passing an object to
Class.contextType
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
class MyClass extends React.Component { componentDidMount() { let value = this.context; /* After the component is mounted, use the value of the MyContext component to perform some side effects */ } componentDidUpdate() { let value = this.context; /* ... */ } componentWillUnmount() { let value = this.context; /* ... */ } render() { let value = this.context; /* Render based on the value of the MyContext component */ } } MyClass.contextType = MyContext;
The’contextType 'property mounted on the class will be reassigned to a React.createContext() Context object created. This property allows you to use this.context to consume the value of the most recent Context. You can access it in any lifetime, including the render function.
Note:
You only pass the
If you are using experimental
1 2 3 4 5 6 7
class MyClass extends React.Component { static contextType = MyContext; render() { let value = this.context; /* Render based on this value */ } }
Context.Consumer
1 2 3
<MyContext.Consumer> {Value => /* render based on the context value */} </MyContext.Consumer>
A React component that allows you to subscribe to changes in context函数式组件You can subscribe to context in.
This method requires a函数作为子元素(function as a child)This function takes the current context value and returns a React NodeThe value passed to the function is equivalent to the value provided by the provider closest to the context in the component treeIf there is no corresponding Provider, the value parameter is equivalent to the defaultValue passed to createContext ()
Attention
Want to learn more about
Context.displayName
The context object accepts a property called’displayName 'of type string. React DevTools uses this string to determine what the context should display.
For example, the following component will be displayed as MyDisplayName in DevTools:
Here we summarize the use and precautions regarding these APIs.
There is one way to create a Context, which is to call’const MyContext = React.createContext (defaultValue); ’
There are two ways to subscribe to Context:
In the component you want to subscribe to ‘static contextType = MyContext;’ but this method can only subscribe to one Context
‘Context. Consumer’: This method requires a function as a child. This function receives the current context value and returns a React node.
The context object accepts a property called’displayName 'of type string. React DevTools uses this string to determine what the context should display.
Example
Dynamic
A more complex solution is to use dynamic values for the theme example above:
render() { //The ThemedButton component inside the ThemeProvider uses the theme value in state, //while external components use the default theme value return ( <Page> <ThemeContext.Provider value={this.state.theme}> <Toolbar changeTheme={this.toggleTheme} /> </ThemeContext.Provider> <Section> <ThemedButton /> </Section> </Page> ); } }
ReactDOM.render(<App />, document.root);
First of all, ‘ThemeContext. Provider’ provides value, so its internal Toolbar uses value instead of the default value of ThemeContext
The’ThemedButton ‘directly used below is not inside any’ThemeContext. Provider’ and directly uses the latest default value.
Update in nested components
It is necessary to update the context from a component that is deeply nested in the component tree. In this scenario, you can pass a function through context to make the consumers component update the context:
theme-context.js
1 2 3 4 5
//Make sure the default value data structure passed to createContext matches that of the invoked consumers! export const ThemeContext = React.createContext({ theme: themes.dark, toggleTheme: () => {} });
theme-toggler-button.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
import {ThemeContext} from './theme-context';
function ThemeTogglerButton() { //The Theme Toggler button not only gets the theme value,//it also gets a toggleTheme function from the context return ( <ThemeContext.Consumer> {({theme, toggleTheme}) => ( <button onClick={toggleTheme} style={{backgroundColor: theme.background}}> Toggle Theme </button> )} </ThemeContext.Consumer> ); }
export default ThemeTogglerButton;
According to our previous analysis, the children of’ThemeContext. Consumer 'are a function component. When the Context changes, it will regenerate the component.
That is to say, when our theme or toggleTheme changes, it will use the changed value to create a new component to replace the old component.
//State also contains an update function, so it is passed to the context provider. this.state = { theme: themes.light, toggleTheme: this.toggleTheme, }; }
render() { The entire state is passed to the provider return ( <ThemeContext.Provider value={this.state}> <Content /> </ThemeContext.Provider> ); } }
Content is rendered in’ThemeContext. Provider ‘, and’ThemeTogglerButton’ is rendered in Content.
The value provided by ThemeContext. Provider is its own state. This state contains the theme and toggleTheme functions.
When we trigger toggleTheme in’ThemeTogglerButton ', we actually modify the outermost state.
This state will be passed as a value by’ThemeContext. Provider ‘, triggering the update of’ThemeTogglerButton’.
This method is essentially no different from state promotion. It allows child components to have a way to change the state of the parent component, but this state does not need to be passed down layer by layer.
Consume multiple
To ensure fast re-rendering of context, React needs to make the context of each consumer component a separate node in the component tree.
A component may consume multiple contexts. function Content() { return ( <ThemeContext.Consumer> {theme => ( <UserContext.Consumer> {user => ( <ProfilePage user={user} theme={theme} /> )} </UserContext.Consumer> )} </ThemeContext.Consumer> ); }
If two or more context values are often used together, you may want to consider creating your own rendering component to provide these values.
Precautions
Because the context uses the reference identity to decide when to render, there may be some pitfalls here. When the provider’s parent component renders, it may trigger unexpected rendering in the consumers component. For example, every time the Provider re-renders, the following code will re-render all the following consumers components because the’value 'attribute is always assigned a new object:
After studying Vue for a long time, I suddenly became a little interested in its old friend React. I went to read its doc preliminarily and found that many things are indeed the same or different from Vue. I used this blog to record my understanding of it. Some notes of doc reading.
At the same time, from the perspective of the Vue source code idea I understand, I will interpret some possible principles behind React
Recently, I read the doc of loopback4 on a whim. To be honest, I vomited a little blood when I read it. It may be that I am too bad. I don’t say the English one. This is okay. There are no strange words, but they are from east to west. Overall, there are two feelings. First, it seems that typing a few lines of command code will come out, but if you don’t understand those strange syntactic sugar words, you can’t type your own code, which is inflexible. Second, doc does not see A complete example, all of which suddenly give you a github link halfway through, asking you to see the project.
But after watching it for so long, let me briefly summarize how to use it to build a project
Recently, I have seen the use of monotonic stack in several different situations. This time, I will systematically summarize the idea of monotonic stack and its use in various situations.
Stack is a very simple data structure, with a logical order of first in and last out, which meets the characteristics of certain problems, such as function call stack.
A monotonic stack is actually a stack, but with some clever logic, every time a new element is added to the stack, the elements in the stack remain in order (monotonically increasing or monotonically decreasing).
The monotonic stack is not very versatile and only deals with a typical problem called the Next Greater (Or Smaller) Element.
The use of monotone stack is also divided into situations:
Divided into two categories from finding the nearest larger or smaller element.
There are three cases from whether to find the next nearest larger (or smaller) element from the left, right, or both sides.
Some time ago, I encountered a problem with browser caching. I didn’t have any ideas at the time. Later, I checked back and found that I had contacted many things, but I didn’t systematically sort them out. I used this blog to sort them out.
The main content is the browser’s strong cache, the mechanism for negotiating the cache, and the corresponding HTTP headers.
In addition, the content related to the browser’s Cache API may be sorted out in the future.