React Higher Order Component explained with Context API 示例

React Higher Order Component explained with Context API example

我正在尝试理解使用具有上下文 api 的高阶组件的示例,已使用 here

因为我对反应和函数式编程还很陌生,所以我不明白这里的实际工作原理。我们正在向函数 withUser 发送一个函数,return 是另一个接收 props.

的函数
function withUser(Component) {
  return function ConnectedComponent(props) {
    return (
      <UserContext.Consumer>
        {user => <Component {...props} user={user} />}
      </UserContext.Consumer>
    );
  };
}

因此,当我们创建 UserAvatar 时,我们正在传递接收 props 和 returns img.

的函数
const UserAvatar = withUser(({ user, size }) => (
  <img
    className={`user-avatar ${size || ""}`}
    alt="user avatar"
    src={user.avatar}
  />
));

所以,基本上在这之后我们可以想象 UserAvatar 是:

const UserAvatar = props => {
        return (
          <UserContext.Consumer>
            {user => <Component {...props} user={user} />}
          </UserContext.Consumer>
        );
      };

其中 Component 是:

({ user, size }) => (
      <img
        className={`user-avatar ${size || ""}`}
        alt="user avatar"
        src={user.avatar}
      />
    )

我希望到目前为止这是正确的,但我不明白的是这一行:

{user => <Component {...props} user={user} />}

当我们已经有了 props 并将 user 传递给 [=19 时,为什么我们需要将其作为一个函数而不只是 return 组件=] 组件从 UserStats 组件向下?

const UserStats = () => (
  <UserContext.Consumer>
    {user => (
      <div className="user-stats">
        <div>
          <UserAvatar user={user} />
          {user.name}
        </div>
        <div className="stats">
          <div>{user.followers} Followers</div>
          <div>Following {user.following}</div>
        </div>
      </div>
    )}
  </UserContext.Consumer>
);

也许最简单的方法是描述一个类似的概念:函数装饰器。

// Start with a function, any function.
let add = (a, b) => a + b;

但现在我们想为参数和 return:

添加日志记录
let addWithLogging = (a, b) => {
  console.log("Args are ", a, b);
  const result = a + b;
  console.log("Result is ", result);
  return result;
}

呕吐。我们简单的一行函数现在被一堆完全偶然添加两个数字的东西复杂化了。如果我们的大多数功能都很简单,并且我们想为所有功能添加日志记录,那么粗略计算就是我们的代码库将翻倍。双杠.

等等,这是 JavaScript,我们有高阶函数,可以提取装饰器:

// Here we take a function f and wrap it. We'll return a function that will
// collect the arguments, log them, perform f on them, log the result, and
// then finally return that result to the caller.
const withLogging = f => (...args) => {
  console.log("Args are ", ...args);
  const result = f(...args);
  console.log("Result is ", result);
  return result;
};

addWithLogging = withLogging(add);

React 对高阶组件使用相同的想法,你有一个组件需要一些额外的功能(经常声明 and/or 进行 AJAX 调用)。您不想让所有这些都使您漂亮的简单可测试纯功能组件复杂化,因此您可以使用更高阶的组件。与上面的日志记录装饰器非常相似,示例中的高阶组件将组件作为参数,并且 returns 是一个匿名的纯功能组件,它实际接收道具并呈现包裹在 UserContext 组件中的传入组件。

可以让 UserContext 组件成为 JSX 的一部分return由其他组件编辑:

const UserAvatar = ({ user, size }) => (
  <UserContext.Consumer>
    <img
      className={`user-avatar ${size || ""}`}
      alt="user avatar"
      src={user.avatar}
    />
  </UserContext.Consumer>
);

但是现在,就像在日志记录示例中一样,您要在每个需要它的组件中重复样板文件。

关于您引用的特定行,可以说您在那里不需要函数,因为据我所知 user 已经在 props 呈现组件时.作为参考,这里是 compiled JSX.

编辑

应该更仔细地阅读代码。

你需要一个函数的原因是因为它是一个上下文消费者。 user 通过上下文提供程序注入,唯一的方法就是给它一个函数来传递参数。