【问题标题】:What classifies as a React functional component?什么归类为 React 功能组件?
【发布时间】:2018-10-20 19:01:44
【问题描述】:

我正在关注 Udemy 上的教程,其中讲师试图解释 HOC。

为了解释 HOC,他创建了一个具有函数组件的函数(至少他是这么说的)。这是代码:

const withClass = (WrappedComponent, className) => {
     return (props) => (
         <div className={className}>
             <WrappedComponent {...props} />        
     </div>

   )
 }

React 文档显示了这个例子:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

并提到:

这个函数是一个有效的 React 组件,因为它接受一个带有数据的“props”(代表属性)对象参数并返回一个 React 元素。我们称此类组件为“函数式”,因为它们实际上是 JavaScript 函数。

[问题]

用更简单的话来说,这样说是否安全: 任何以 props 作为参数的函数都可以归类为函数组件?如果没有,有人可以简要解释一下 React 中的功能组件吗?

【问题讨论】:

  • ...并返回有效的 React 节点或 null。
  • Tomasz 我想我明白了你的意思,但可以肯定的是,你能在答案部分详细解释一下吗?

标签: javascript reactjs


【解决方案1】:

任何以 props 作为参数的函数都可以归类为 一个功能组件?

不,props 只是函数参数,就像所有其他普通函数参数一样。因此,如果我们定义任何接受参数的函数,它不一定是 React 函数式组件,就像这不是 React 组件:

const Testing = props => {
   const a = 10;
   return a * props.a;
}

重要的部分是“如果该组件返回一个 React 元素”,那么它才会是一个 React 函数式组件。

为了更清楚,只需在单独的文件中定义以下函数;当你转译时它不会抛出任何错误:

const Test = props => props.key * 10;

但是如果你在一个单独的文件中定义这个下面的组件而不导入 React,它会抛出错误,React 没有定义,当你编译时:

const Test = props => <div>{props.key * 10}</div>;

因为 JSX 将被转换为 React.createElement(....) 并且需要 React。上述组件的converted version 将是:

var Test = function Test(props) {
  return React.createElement(
    "div",
    null,
    props.key * 10
  );
};

我会建议,使用Babel REPL 并定义两个函数并检查输出。

【讨论】:

    【解决方案2】:

    当你创建这样的函数时:

    function MyComponent() {
      return null;
    }
    

    这是一个普通的 JavaScript 函数,不是吗?但它可以变成一个 React 组件。如果你使用 react-preset 允许你使用 JSX 语法,你可以把这个函数变成一个呈现 null 的组件:

    <Welcome /> 
    

    将产生:

    React.createElement(MyComponent, null);
    

    因此,函数式组件是从函数创建的组件,而不是通过扩展 React 基类 (React.Component)。

    这只是定义它们的两种方法。您可以通过Babel online transpiler 到处玩,看看幕后有什么。

    【讨论】:

    【解决方案3】:

    是的,以 props 作为参数的函数可以归类为函数式无状态反应组件。

    这个函数应该返回一个有效的组件答案;例如,React 节点、数组、数字、字符串或 null。

    这样的函数没有状态,你不能用它设置组件生命周期方法。

    您的 JSX 代码被转换为 React.createElement 函数,该函数接收“本机”组件,例如 div、span 或函数。

    为了澄清我的答案,我将包含最简单的 React.createElement 实现(Dan Abramov 前段时间在 JS Bin 上发布了这段代码):

    // Necessary for JSX to work
    window.React = {
      createElement(type, props, ...children) {
        return {
          type,
          props: {
            ...props,
            children: children || props.children
          }
        }
      }
    };
    
    // What kind of node are we dealing with?
    function getNodeKind(node) {
      if (node === false || node == null) {
        // A hole: false, null, undefined
        return 'EMPTY';
      }
      if (typeof node === 'string' || typeof node === 'number') {
        // Text or number: 'Hello', 42
        return 'TEXT';
      }
      if (Array.isArray(node)) {
        // An array of nodes!
        return 'ARRAY';
      }
      if (typeof node.type === 'string') {
        // An element describing “host” (e.g. DOM) component: <div />
        return 'HOST';
      }
      if (typeof node.type === 'function') {
        // An element describing “composite” (user-defined) component: <Foo />
        return 'COMPOSITE';
      }
      throw new Error('Weird node: ' + node);
    }
    
    // To render a host element like <div />, we’ll generate
    // its tag markup and render children inside.
    // This is a simple implementation and doesn’t attempt to escape anything.
    function renderHostElementToString(el) {
      // Separate children from attributes
      const { children, ...otherProps } = el.props;
    
      // Create an attribute string for markup
      let attributes = Object.keys(el.props)
        .map(propName => propName + '=' + el.props[propName])
        .join(' ');
      
      // If attributes exist, prepend a space to separate from tag
      if (attributes) {
        attributes = ' ' + attributes;
      }
      
      // Create tag strings for markup
      // For host elements, type is the tag name
      const openingTag = '<' + el.type + attributes + '>';
      const closingTag ='</' + el.type + '>';
      
      return (
        openingTag +
        // Render children recursively!
        renderToString(children) +
        closingTag
      );
    }
    
    // To render a composite component like <Foo />,
    // we’ll call its type (`Foo`) with its props.
    // We will then recursively render it.
    function renderCompositeElementToString(el) {
      const renderedEl = el.type(el.props);
      return renderToString(renderedEl);
    }
    
    // Handle different types differently.
    function renderToString(node) {
      var kind = getNodeKind(node);
      switch (kind) {
        case 'EMPTY':
          return '';
        case 'TEXT':
          return node.toString();
        case 'ARRAY':
          // Render each of them
          return node.map(renderToString).join('');
        case 'HOST':
          // <div />
          return renderHostElementToString(node);
        case 'COMPOSITE':
          // <Foo />
          return renderCompositeElementToString(node);
      }
    }
    
    // Let’s give it a try!
    
    function Badge({ children }) {
      return (
        <div>
          <hr />
          {children}
          <hr />
        </div>
      );
    }
    
    function UserInfo({ name, location }) {
      return (
        <Badge>
          {name} lives in {location}.
        </Badge>
      );
    }
    
    function App() {
      return (
        <div>
          <h1>
            Hello, React!
          </h1>
          <UserInfo
            name="Dan"
            location="London"
          />
        </div>
      );
    }
    
    document.body.innerHTML = renderToString(<App />);

    【讨论】:

      【解决方案4】:

      React 中的一个功能组件:

      • 用于呈现静态数据
      • 无法处理获取数据
      • 易写

      例子:

      const Header = () => {
        return <Text>Hello World!</Text>
      }
      

      【讨论】:

        猜你喜欢
        • 2023-04-04
        • 1970-01-01
        • 2021-03-24
        • 2022-11-30
        • 1970-01-01
        • 2021-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多