ReactJS 正确使用有状态和无状态组件的方法?

Posted

技术标签:

【中文标题】ReactJS 正确使用有状态和无状态组件的方法?【英文标题】:ReactJS correct way to use of stateful and stateless components? 【发布时间】:2020-05-25 11:03:16 【问题描述】:

我已经开始学习 ReactJS 并且有一个关于无状态和有状态组件的问题。一般来说,我遵循组件和容器的分离,如下所示。有状态的函数在组件文件夹和容器文件夹下的其他逻辑操作。 folder structure

让我们想想 Material UI 下拉列表。

import React from 'react';
import  makeStyles  from '@material-ui/core/styles';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl';
import Select from '@material-ui/core/Select';

const useStyles = makeStyles(theme => (
  button: 
    display: 'block',
    marginTop: theme.spacing(2),
  ,
  formControl: 
    margin: theme.spacing(1),
    minWidth: 120,
  ,
));

export default function ControlledOpenSelect() 
  const classes = useStyles();
  const [age, setAge] = React.useState('');
  const [open, setOpen] = React.useState(false);

  const handleChange = event => 
    setAge(event.target.value);
  ;

  const handleClose = () => 
    setOpen(false);
  ;

  const handleOpen = () => 
    setOpen(true);
  ;

  return (
    <div>    
      <FormControl className=classes.formControl>
        <InputLabel id="demo-controlled-open-select-label">Age</InputLabel>
        <Select
          labelId="demo-controlled-open-select-label"
          id="demo-controlled-open-select"
          open=open
          onClose=handleClose
          onOpen=handleOpen
          value=age
          onChange=handleChange
        >
          <MenuItem value="">
            <em>None</em>
          </MenuItem>
          <MenuItem value=10>Ten</MenuItem>
          <MenuItem value=20>Twenty</MenuItem>
          <MenuItem value=30>Thirty</MenuItem>
        </Select>
      </FormControl>
    </div>
  );

为了打开和关闭下拉列表handleClose()handleOpen() 方法改变打开状态,这意味着它是有状态的组件。但是没有其他变化(省略年龄设置)。它似乎是可重用的组件,但包含具有非常简单操作的状态,例如打开和关闭。我应该放在哪个文件夹?容器还是组件?

其实除了文件夹选择之外,我可以将打开状态作为回调函数,将打开状态作为道具。但我认为在每个容器中执行此操作可能有点矫枉过正,并且因为只是打开下拉列表而重新渲染父容器(React.memo 可以处理它,但在任何地方都使用它似乎很奇怪)。

1- 使用简单操作的正确方法是什么?将功能作为道具或在组件中使用状态?

2- 如果我使用道具,渲染是否会导致性能问题,因为整个其他组件都会渲染?

提前致谢。

【问题讨论】:

【参考方案1】:

容器组件:

这些是执行繁重逻辑的组件,主要是基于路由或(更好地说是重)基于逻辑的组件。

功能组件:

这些功能很小(或可能很大)可用,但主要目的是它们可以在多个容器组件中使用,并且事件可能在其他功能组件中,功能组件的目的是信誉,它们保持某种状态(如在你的情况下保持一个简单的钩子状态来跟踪切换)我可以说完全没问题

大多数时候,您会发现自己在路由级别使用容器组件,并连接 Redux(我也应该注意,这些天不鼓励这样做)以及嵌套在子组件中的许多其他功能组件。

为了回答你的问题,我可以这么说:

    对于简单的操作,您不要必须在父级中保持状态 组件并将其传递给您的功能组件, 这会导致您将很多道具传递给您的子组件 并使项目维护变得如此棘手并导致代码错误, 在子组件中保持简单状态是完全可以的 我觉得没那么多,如果你只传递简单的道具......

【讨论】:

谢谢!,我也是这么想的,微小的操作也可以。正如您所说,在路由级别使用容器组件容器主要在路由发生时使用。也许子容器可以用来降低复杂性。为什么你说我也应该注意到这些天不鼓励 根据 Dan Abromov 的文章,我读到了一些我不记得的地方 :))))【参考方案2】:

在功能组件中使用新功能、反应钩子和上下文比使用基于类的组件或询问有状态或无状态组件更好

【讨论】:

这与我的问题无关。如您所见,我使用了钩子。也许可以使用上下文,但对于切换来说是不必要的。

以上是关于ReactJS 正确使用有状态和无状态组件的方法?的主要内容,如果未能解决你的问题,请参考以下文章

4.有状态组件和无状态组件

如何在 Reactjs 的组件状态下使用 OOP?

在 React 中分离有状态和无状态组件的线应该在哪里?

重新渲染 Reactjs 后,父组件立即失去状态

ReactJS:为啥将组件初始状态传递给一个反模式?

reactjs - 状态更改后组件不呈现[重复]