【问题标题】:Refactor a React component from function to ES6 class将 React 组件从函数重构为 ES6 类
【发布时间】:2016-11-10 01:39:38
【问题描述】:

我是 ES6 新手。 对编写 React 组件的不同方式感到有些困惑。 我从“React.createClass”开始,然后移至使用 ES6 类语法“扩展 React.Component”。

按照 Redux 教程,现在我看到他们以这种方式定义组件

import React, { PropTypes } from 'react'

const Todo = ({ onClick, completed, text }) => (
    <li onClick={onClick} style={{ textDecoration: completed ? 'line-through' : 'none' }} >
        {text}
    </li>
)

Todo.propTypes = {
    onClick: PropTypes.func.isRequired,
    completed: PropTypes.bool.isRequired,
    text: PropTypes.string.isRequired
}

export default Todo

我怎样才能重构这个“函数”移动到一个扩展 React.component 的 ES6 类?我猜返回 JSX 是 render() 方法,不是吗? onClick、completed、文本参数呢?

谢谢

【问题讨论】:

    标签: javascript reactjs ecmascript-6


    【解决方案1】:

    对于你的组件,实际上最好将其设为纯函数,而不是 ES6 类,因为它可以作为其props 的函数进行渲染,并且不维护状态。不过,您仍然可以使用 ES6 语法(导出、箭头函数等)。

    Facebook's explanation:“在理想情况下,您的大多数组件将是无状态函数,因为将来我们还可以通过避免不必要的检查和内存分配来针对这些组件进行性能优化。这是推荐的模式,如果可能的话。”

    import { PropTypes } from 'react'
    
    function Todo = (props) => (
        <li onClick={props.onClick} style={{ textDecoration: props.completed ? 'line-through' : 'none' }} >
            {props.text}
        </li>
    )
    
    Todo.propTypes = {
        onClick: PropTypes.func.isRequired,
        completed: PropTypes.bool.isRequired,
        text: PropTypes.string.isRequired
    }
    
    export default Todo
    

    【讨论】:

    • 这正是应该做的。仅仅因为您可以将组件编写为 ES6 类并不意味着所有组件都应该是类。
    • 我支持您的解决方案。我不知道你可以不必为组件中的道具使用 PropTypes.shape。
    • 避免回答问题:“做 X 的最好方法就像 ABC,因此这里是 ABC” - 他想要纯函数版本的 ES6 版本,而不是重复他的确切问题参考。
    • 不应该是const Todo = ...(或function Todo(props) { ... })而不是function Todo = ...吗?
    【解决方案2】:

    等效的 ES6 语法是:

    import React, { Component, PropTypes } from 'react'
    
    class Todo extends Component {
      render() {
        const { onClick, completed, text } = this.props
    
        return (
          <li onClick={onClick} style={{ textDecoration: completed ? 'line-through' : 'none' }} >
              {text}
          </li>
        )
      }
    }
    Todo.propTypes = {
      onClick: PropTypes.func.isRequired,
      completed: PropTypes.bool.isRequired,
      text: PropTypes.string.isRequired
    }
    
    export default Todo
    

    如果您使用babel 转译您的代码并且您拥有class properties transform,那么您可以执行以下操作:

    import React, { Component, PropTypes } from 'react'
    
    class Todo extends Component {
      static propTypes = {
        onClick: PropTypes.func.isRequired,
        completed: PropTypes.bool.isRequired,
        text: PropTypes.string.isRequired
      }
    
      render() {
        const { onClick, completed, text } = this.props
    
        return (
          <li onClick={onClick} style={{ textDecoration: completed ? 'line-through' : 'none' }} >
              {text}
          </li>
        )
      }
    }
    
    export default Todo
    

    为了清楚起见,第二个示例不能被视为“标准 ES6”,但是我发现静态属性非常干净,所以我认为也值得展示这种方法。

    【讨论】:

    • OP 要求一个 ES6 类,你的回答是语法错误。
    【解决方案3】:

    从 ES6 迁移到 TypeScript,对于 React 17 及更高版本,您可以这样做:

    import type { FC } from "react";
    
    interface TodoProps {
      onClick: () => void;
      hasCompleted: () => boolean;
      text: string;
    }
    
    const Todo: FC<TodoProps> = ({ onClick, hasCompleted, text }) => (
      <li
        onClick={onClick}
        style={{ textDecoration: hasCompleted ? "line-through" : "none" }}
      >
        {text}
      </li>
    );
    
    export default Todo;
    

    如果您不想要 implicit 孩子,您可以删除 import type 行并重写如下:

    const Todo = ({ onClick, hasCompleted, text }: TodoProps) => (
    

    但是,如果您这样做了,您还需要将children 添加到类型声明中,并花时间尝试找出应该如何输入它——如果假设使用FC,则不需要使用children

    有关在 TypeScript 中声明函数的更多信息,请访问 TypeScript 文档中的More on Functions

    【讨论】:

      猜你喜欢
      • 2018-02-28
      • 1970-01-01
      • 2017-11-21
      • 2021-11-24
      • 2022-01-17
      • 2020-01-02
      • 2017-04-19
      相关资源
      最近更新 更多