【问题标题】:React partial render反应部分渲染
【发布时间】:2018-03-31 14:50:19
【问题描述】:

让我们来看看一些必须渲染的琐碎反应组件:
1)文本字段(托管一个,连接到状态)
2)任务列表(也通过连接到状态的数组映射)
3) 按钮,单击时将新项目从文本字段添加到数组

https://stackblitz.com/edit/react-glpzqn?embed=1&file=index.js

当文本字段被更新时(textChange 事件)=> 然后状态被更新 => 强制渲染(在文本字段中的每个按键上)。

这是不需要的渲染,我只想在单击按钮时渲染,将项目添加到数组中,最后在屏幕上渲染新列表。

所以我只想在添加到列表中的项目上强制渲染,而不是在文本更改时强制渲染。

我可以透露的一些解决方案是:
1) 将输入输入另一个组件,因此文本更改不会影响列表呈现。
2) 将输入字段更改为非托管并在单击按钮时手动检索文本。

我猜是否有一些更优雅的解决方案而不更改组件? 可能是通过使用一些 HOC 或相同的?

【问题讨论】:

  • 你实际上并没有打电话给forceUpdate,是吗?此外..您知道每次调用渲染时react实际上都不会重新绘制DOM..您可能会以60fps的速度调用渲染,如果只有输入发生变化,则只有输入被重新渲染,而不是页面上的所有内容。最后,您只需要一个简单的shouldComponentUpdate 即可节省一些周期,尽管通常是不必要的
  • 但我希望在文本更改时更新组件的状态以同步字段值,否则不会更改。但是当文本字段状态改变时,它会在每个字母改变后调用渲染。我不能使用 shouldComponentUpdate,因为我只想在文本更改后进行组件更新,否则它会阻止它。你是对的,只有必要的部分被重新绘制,但和解(检查要更新的内容)以任何方式发生,我不想要。所以问题不是重绘,而是重新计算我想要阻止的更改。
  • 为什么要阻止这种情况?你是在制作高功率动画还是什么?这是非常过早的优化。无论如何。当状态改变时,只有子节点会得到协调,因此您可以对树进行建模,以便仅重新呈现状态改变的组件。我认为您应该发布一些代码,否则很难写出准确的答案
  • 是的,一种解决方案是将输入字段以自己的状态带到自己的组件中,因此实际上不会渲染列表(也不会重新绘制),仅在按钮单击回调时。但是如果我们在一个组件中有列表和输入,可能有一些方法可以让列表呈现远离,直到我单击按钮而不分成 2 个组件?
  • 这是一个非常简单的控件:stackblitz.com/edit/react-glpzqn?embed=1&file=index.js 只是为了说明我的意思

标签: reactjs


【解决方案1】:

最简单的解决方案是使用shouldComponentUpdate。不是在整个组件上,而是在与它们不相关的道具发生变化时不想渲染的组件上:

class List extends Component {
  shouldComponentUpdate(nextProps) {
    return nextProps.items !== this.props.items
  }

  render() {
    // will only fire when the tasks array has changed
    console.log('list rendered')
    return this.props.items.map(item => (
      <div key={item}>{item}</div>
    ))
  }
}

这也只是一个简单的检查,您可以通过PureComponent免费获得

class List extends PureComponent {
  render() {
    return this.props.items.map(item => (
      <div key={item}>{item}</div>
    ))
  }
}

大家一起:

import React, { Component, PureComponent } from 'react';
import { render } from 'react-dom';

class List extends PureComponent {
  render() {
    console.log('list rendered')
    return this.props.items.map(item => (
      <div key={item}>{item}</div>
    ))
  }
}

class App extends Component {
  // do not need constructor if already using class arrows
  state = {
    input: "",
    tasks: []
  };

  addTask = () => {
    this.setState({
      tasks: [...this.state.tasks, this.state.input],
      input: ""
    });
  }

  setValue = event => {
    this.setState({
      input: event.target.value
    });
  }

  render() {
    return (
      <div>
        <List items={this.state.tasks} />
        <input onChange={this.setValue} value={this.state.input} />
        <button onClick={this.addTask}>Add</button>
      </div>
    );
  }
}

render(<App />, document.getElementById('root'));

stackblitz solution

【讨论】:

  • 谢谢!一切都是100%!此外,我们可以将它们保存在一个组件中并将输入更改为非托管。这是我假设的两种解决方案。但可能存在一些更优雅的吗? (不分成 2 个组件或将输入扔到非托管状态)
  • 箭头函数使用词法this。为什么您通过提供不受支持且没有意义的语法来使示例过于复杂?
  • @WillHoskings 不受谁的支持? JSX 已经完全不受所有浏览器的支持......在 React 代码中使用类箭头属性是完全常见的,甚至官方文档也建议这样做。此外,现在一切都在朝着 hooks 方向发展,并且 react 中的类将变得晦涩难懂,所以这个讨论将无关紧要
  • @WillHoskings 也许你可以简单地详细说明一下。渲染中需要箭头函数,如果不是类方法需要在构造函数中绑定,或者类方法使用箭头函数定义为属性。我选择了后者,因为它是最常见的
  • 一个箭头函数使用词法this它现在下沉了吗
【解决方案2】:

只需将 onChange 替换为 onBlur,如下所示,以下更改只会在您离开输入后立即呈现。

  <input onBlur={this.setValue} />

【讨论】:

    猜你喜欢
    • 2017-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多