首页 > 解决方案 > React:更新子组件而不重新渲染父组件

问题描述

下面是一个简单的例子:

const { Component } = React
const { render } = ReactDOM

const Label = ({ text }) => (
  <p>{text}</p>
)

const Clock = ({ date }) => (
  <div>{date.toLocaleTimeString()}</div>
)

class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      date: new Date()
    }
  }
  
  componentDidMount() {
    this.interval = setInterval(
      () => this.setState({ date: new Date() }),
      1000
    )
  }
  
  componentWillUnmount() {
    clearInterval(this.interval)
  }
  
  updateTime() {
    
  }
  
  render() {
    return (
      <div>
        <Label text="The current time is:" />
        <Clock date={this.state.date} />
      </div>
    )
  }
  
}

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

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

this.setState({ date: new Date() })每秒被调用一次,用当前时间更新时钟。据我所知,setState调用 App 上的 render 方法会导致整个组件被重新渲染,包括标签。

有没有办法在不重新渲染整个 App 组件的情况下将日期传递给 Clock(导致它被重新渲染)?这对性能有多大影响?

标签: javascriptreactjs

解决方案


当您想更新子代而不更新父代时,状态必须在子代中。您可以将状态 getter / setter 从子级传递给父级,以便能够读取和更新它:

function Child({onMount}) {
  const [value, setValue] = useState(0);

  useEffect(() => {
    onMount([value, setValue]);
  }, [onMount, value]);


  return (
    <div>
      {value}
    </div>    
  );
};


function Parent() {

  let value = null;
  let setValue = null;
  
  const onChildMount = (dataFromChild) => {
    value = dataFromChild[0];
    setValue = dataFromChild[1];
  };

  // Call setValue to update child without updating parent

  return (
    <div>
      <Child onMount={onChildMount}/>
    </div>    
  );
};

由于const [value, setValue] = useState(0);在 中Child,更新值时只有子组件会重新渲染。此外,由于ParentreceivevaluesetValueat onChildMount,父级可以使用它们来更新子级,而无需重新渲染父级。


推荐阅读