当child.shouldComponentUpdate()返回false时,React useState()挂钩不会更新状态

时间:2020-07-05 16:36:02

标签: reactjs react-hooks

我已经开始阅读有关React Hooks的文章,并试图重写一些小的组件以使用它们,但是设置状态存在问题。基本上,当子组件<Content/>false中始终返回shouldComponentUpdate时,将调用父组件(<App/>.setShow),但不会更新状态,并且<Content/>没有呈现。

我在下面准备了一个最小的工作示例,其中<App/>是基于React Hoos的组件,而<App2/>是基于等效类的Component。后者有效,因此显然我没有得到一些细微之处。

const {useState} = React;

class Panel extends React.Component {
   shouldComponentUpdate() { return false; } 
   render() { return (<button onClick={this.props.onClick}>Toggle</button>) }
}

class Content extends React.Component {
  render() { return <div>Content</div> }
}

const App = (props) => {
  const [show, setShow] = useState(true);

  const toggle = () => {
    console.log("Toggling visibility!", show);
    setShow(!show);
  }

  console.log("[App] render()");
  return (<div >
    <h1>Hi at {Date.now()}</h1>
    <Panel onClick={toggle} />
    {show && <Content /> }
  </div>)
}

class App2 extends React.Component {
  state = { show: true }

  render() {
    const toggle = () => {
      console.log("[App] toggle", this.state.show)
      this.setState({ show: !this.state.show })
    }

    console.log("[App] render()");
    return (<div >
      <h1>Hi at {Date.now()}</h1>
      <Panel onClick={toggle} />
      {this.state.show && <Content />}
    </div>)
  }
}

ReactDOM.render(<div> <App/> <App2/> </div>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>

<div id="app">
</app>

1 个答案:

答案 0 :(得分:3)

您需要使用functional updates,因为您在show函数中的toggle的值是closure

之所以会发生关闭,是因为shouldComponentUpdate总是返回false,因此,在第一次渲染时,this.props.onClick的值将具有过时的状态show === true,在后续情况下不会更改渲染。

const App = () => {
  const [show, setShow] = useState(true);

  // Closure on value of show
  // const toggle = () => {
  //   console.log("Toggling visibility!", show);
  //   setShow(!show);
  // }

  const toggle = () => {
    setShow(prevState => {
      console.log("Toggling visibility!", prevState);
      return !prevState;
    });
  };

  console.log("[App] render()");
  return (
    <div>
      <h1>Hi at {Date.now()}</h1>
      <Panel onClick={toggle} />
      {show && <Content />}
    </div>
  );
};

Edit gallant-saha-9z8eu