React Source Reading - 4_033

Keywords: Javascript React Attribute less

React Source Reading-4

Context

Context provides a way to pass data through a component tree without having to pass props attributes manually at each level.

When to use Context

Context aims to share data that can be considered "global" within a component tree, such as currently authenticated users, topics or preferred languages.

  const context: ReactContext<T> = {
    $$typeof: REACT_CONTEXT_TYPE,
    _calculateChangedBits: calculateChangedBits,
    _currentValue: defaultValue,
    _currentValue2: defaultValue,
    // Used to track how many concurrent renderers this context currently
    // supports within in a single renderer. Such as parallel server rendering.
    _threadCount: 0,
    // These are circular
    Provider: (null: any),
    Consumer: (null: any),
  };

Example:

class App extends React.Component {
  render() {
    return <Toolbar theme="dark" />;
  }
}

  // The Toolbar component accepts an additional "theme" attribute and passes it to the ThemedButton component.
  // If every single button in the application needs to know the value of the theme, it will be a very troublesome thing.
  // Because this value layer must be passed to all components.

function Toolbar(props) {
  return (
    <div>
      <ThemedButton theme={props.theme} />
    </div>
  );
}
class ThemedButton extends React.Component {
  render() {
    return <Button theme={this.props.theme} />;
  }
}

Using context, we can avoid passing props through intermediate elements:

const ThemeContext = React.createContext('light');

class App extends React.Component {
  render() {
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

// 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.

function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {.
  static contextType = ThemeContext;
  render() {
    return <Button theme={this.context} />;
  }
}

Considerations before using Context

1.Context's main application scenario is that many components at different levels need to access the same amount of data. Use cautiously, as this can make components less reusable.

component composition is sometimes a better solution than context if you just want to avoid passing some attributes layer by layer.

<Page user={user} avatarSize={avatarSize} />
// To render...
<PageLayout user={user} avatarSize={avatarSize} />
// To render...
<NavigationBar user={user} avatarSize={avatarSize} />
// To render...
<Link href={user.permalink}>
  <Avatar user={user} size={avatarSize} />
</Link>

A context less solution is to pass on the Avatar component itself so that the intermediate component does not need to know props such as user or avatarSize:

function Page(props) {
  const user = props.user;
  const userLink = (
    <Link href={user.permalink}>
      <Avatar user={user} size={props.avatarSize} />
    </Link>
  );
  return <PageLayout userLink={userLink} />;
}

// Now, we have components like this:
<Page user={user} avatarSize={avatarSize} />
// To render...
<PageLayout userLink={...} />
// To render...
<NavigationBar userLink={...} />
// To render...
{props.userLink}

Sometimes, however, many components at different levels in the component tree need to access the same batch of data. Context allows you to "broadcast" the data to all components under the component tree, and all components can access the data, as well as subsequent data updates. Common scenarios using context include managing current locale s, theme s, or some cached data, which is much simpler than alternatives.

React.createContext

const MyContext = React.createContext(defaultValue);

Create a Context object. When React renders a component that subscribes to the Context object, the component reads the current context value from the matching Provider closest to itself in the component tree.

The defaultValue parameter of a component will only take effect if it is not matched to the Provider in the tree in which it is located. This helps to test components without using Provider to wrap them. Note: When undefined is passed to the value of the Provider, the defaultValue of the consumer component will not take effect.

Context.Provider

Each Context object returns a Provider React component that allows the consumer component to subscribe to context changes.

  context.Provider = {
    $$typeof: REACT_PROVIDER_TYPE,
    _context: context,
  };

Provider receives a value attribute and passes it to the consumer component. A Provider can correspond to multiple consumer components. Multiple providers can also be nested, and the inner layer will cover the outer data.

When the value value of the Provider changes, all consumer components within it will be re-rendered. Provider and its internal consumer components are not subject to the shouldComponentUpdate function, so the consumer component can be updated when its ancestor component exits the update.

New and old values are detected to determine changes, using the same algorithm as Object.is.

Class.contextType

class MyClass extends React.Component {
  componentDidMount() {
    let value = this.context;
    /* After the component mount is complete, use the values of the MyContext component to perform some side-effects */
  }
  componentDidUpdate() {
    let value = this.context;
    /* ... */
  }
  componentWillUnmount() {
    let value = this.context;
    /* ... */
  }
  render() {
    let value = this.context;
    /* Rendering Based on the Value of MyContext Component */
  }
}
MyClass.contextType = MyContext;

The contextType attribute mounted on the class is reassigned to a Context object created by React.createContext(). This allows you to use this.context to consume the value on the latest Context. You can access it in any lifecycle, including render functions.

Multiple cases

https://zh-hans.reactjs.org/d...

class MyClass extends React.Component {
  static contextType = MyContext;
  render() {
    let value = this.context;
    /* Rendering based on this value */
  }
}

Context.Consumer

const Consumer = {
  $$typeof: REACT_CONTEXT_TYPE,
  _context: context,
  calculateChangedBits: context._calculateChangedBits,
  };
<MyContext.Consumer>
  {value => /* Rendering Based on context Value*/}
</MyContext.Consumer>

Here, React components can also subscribe to context changes. This allows you to subscribe to context in functional components.

This requires a function as a child. This function receives the current context value and returns a React node. The value passed to the function is equivalent to the value provided by the Provider closest to the context in the component tree up. If there is no corresponding Provider, the value parameter is equivalent to the defaultValue passed to createContext().

http://react.html.cn/docs/con...

Posted by rob_maguire on Thu, 10 Oct 2019 04:38:13 -0700