谁能解释为啥这适用于类组件而不是功能组件?

Posted

技术标签:

【中文标题】谁能解释为啥这适用于类组件而不是功能组件?【英文标题】:Can anyone explain why this works with a class component but not a functional component?谁能解释为什么这适用于类组件而不是功能组件? 【发布时间】:2021-03-14 20:13:00 【问题描述】:

基本上,我有几个按钮。我希望用户能够选择多个按钮。

我尝试使用功能组件并使用 useState 挂钩将按钮状态存储为对象。单击按钮时状态会相应更新,但按钮的道具不会更新。当 props.isActive 发生变化时,我尝试使用 useEffect 重新渲染组件,但这不起作用。

使用类组件,这完全符合预期。我只是想了解为什么会这样。如果有人能提供见解,我将不胜感激。谢谢。

功能组件

const View = (props) => 
  var [buttons, setButtons] = useState([
     name: "Small", isActive: false ,
     name: "Large", isActive: false ,
  ]);
  const handleClick = (index) => 
    let tmp = buttons;
    tmp[index].isActive = !tmp[index].isActive;
    return setButtons(tmp);
  ;
  return (
      <div>
            buttons.map((e, index) => 
              return (
                <MyButtonComponent
                  key=index
                  name=e.name
                  isActive=e.isActive
                  onClick=() => handleClick(index)
                />
              );
            )
    </div>
  );
;

类组件

class View extends Component 
  state = 
    btn: [
       name: "Small", isActive: false ,
       name: "Large", isActive: false ,
    ],
  ;
  handleClick = (index) => 
    let tmp = this.state.btn;
    tmp[index].isActive = !tmp[index].isActive;
    return this.setState( ...this.state, btn: tmp );
  ;
  render() 
    return (
            <div>
              this.state.btn.map((e, index) => 
                return (
                  <MyButtonComponent
                    key=index
                    name=e.name
                    isActive=e.isActive
                    onClick=() => this.handleClick(index)
                  />
                );
              )
            </div>
    );
  

【问题讨论】:

【参考方案1】:

您正在对旧数组进行变异,然后使用变异数组设置状态。无论您使用的是类组件还是函数组件,这在 react 中都不是一个好主意。类组件让你侥幸逃脱,但函数组件将之前的状态与之后的状态进行比较,发现它们是同一个数组,因此它跳过了渲染。

要解决此问题,您应该创建一个新状态而不是改变旧状态。改变这个:

let tmp = buttons;
tmp[index].isActive = !tmp[index].isActive;
return setButtons(tmp);

到这里:

// Create a copy of the array
let tmp = [...buttons]; 
// Also copy the item you want to change
tmp[index] = 
  ...tmp[index],
  active: !tmp[index].active

setState(tmp);

【讨论】:

啊哈,这很有道理。谢谢你。您的解决方案效果很好:)【参考方案2】:

您正在更新引用并将相同的引用设置为 state(setButtons(tmp)),其中 react thinks, 数组由于浅比较而没有更改。您需要使用新的参考。像下面这样

    let tmp = buttons; <-- problem is here, reference 
    tmp[index].isActive = !tmp[index].isActive;
    return setButtons(tmp); <-- and updating same `reference`
   const handleClick = (index) => 
     buttons[index].isActive = !buttons[index].isActive;
     return setButtons([...buttons]); <-- this will work
   ;

【讨论】:

感谢您的解释,我很感激。这也很好用!

以上是关于谁能解释为啥这适用于类组件而不是功能组件?的主要内容,如果未能解决你的问题,请参考以下文章

是否有适用于类组件的 React Material-UI makeStyles() 函数的非挂钩替代方案

为啥我不能更新函数组件中的状态(使用钩子)?

为啥没有适用于 python 的 Spring DI(组件生命周期)框架?

React Hooks用法大全

视图组件(Component)

为啥 getElementsByClassName 在 React 功能组件中返回未定义?