React高级特性之Context

Context提供了一种不需要手动地通过props来层层传递的方式来传递数据。

正文

在典型的React应用中,数据是通过props,自上而下地传递给子组件的。但是对于被大量组件使用的固定类型的数据(比如说,本地的语言环境,UI主题等)来说,这么做就显得十分的累赘和笨拙。Context提供了一种在组件之间(上下层级关系的组件)共享这种类型数据的方式。这种方式不需要你手动地,显式地通过props将数据层层传递下去。

什么时候用Context?

这一小节,讲的是context适用的业务场景。

Context是为那些可以认定为【整颗组件树范围内可以共用的数据】而设计的。比如说,当前已认证的用户数据,UI主题数据,当前用户的偏好语言设置数据等。举个例子,下面的代码中,为了装饰Button component我们手动地将一个叫“theme”的prop层层传递下去。 传递路径是:App -> Toolbar -> ThemedButton -> Button

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

function Toolbar(props) {
   
  // The Toolbar component must take an extra "theme" prop
  // and pass it to the ThemedButton. This can become painful
  // if every single button in the app needs to know the theme
  // because it would have to be passed through all components.
  return (
    <div>
      <ThemedButton theme={
   props.theme} />
    </div>
  );
}

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

使用context,我们可以跳过层层传递所经过的中间组件。现在我们的传递路径是这样的:App -> Button

// Context lets us pass a value deep into the component tree
// without explicitly threading it through every component.
// Create a context for the current theme (with "light" as the default).
const ThemeContext = React.createContext('light');

class App extends React.Component {
   
  render() {
   
    // Use a Provider to pass the current theme to the tree below.
    // Any component can read it, no matter how deep it is.
    // In this example, we're passing "dark" as the current value.
    return (
      <ThemeContext.Provider value="dark">
        <Toolbar />
      </ThemeContext.Provider>
    );
  }
}

// A component in the middle doesn't have to
// pass the theme down explicitly anymore.
function Toolbar(props) {
   
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

class ThemedButton extends React.Component {
   
  // Assign a contextType to read the current theme context.
  // React will find the closest theme Provider above and use its value.
  // In this example, the current theme is "dark".
  static contextType = ThemeContext;
  render() {
   
    return <Button theme={
   this.context} />;
  }
}

在你用Context之前

这一小节,讲的是我们要慎用context。在用context之前,我们得考虑一下当前的业务场景有没有第二种技术方案可用。只有在确实想不出来了,才去使用context。

Context主要用于这种业务场景:大量处在组件树不同层级的组件需要共享某些数据。实际开发中,我们对context要常怀敬畏之心,谨慎使用。因为它犹如潘多拉的盒子,一旦打开了,就造成很多难以控制的现象(在这里特指,context一旦滥用了,就会造成很多组件难以复用)。

如果你只是单纯想免去数据层层传递时对中间层组件的影响,那么组件组合是一个相比context更加简单的技术方案。

举个例子来说,假如我们有一个叫Page的组件,它需要将useravatarSize这两个prop传递到下面好几层的Link组件和Avatar组件:

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

我们大费周章地将useravatarSize这两个prop传递下去,最终只有Avatar组件才真正地用到它。这种做法显得有点低效和多余的。假如,到后面Avatar组件需要从顶层组件再获取一些格外的数据的话,你还得手动地,逐层地将这些数据用prop的形式来传递下去。实话说,这真的很烦人。

不考虑使用context的前提下,另外一种可以解决这种问题的技术方案是:A

你可能感兴趣的:(reactjs)