在React.js表单组件中使用state或refs?

gab*_*ssi 108 reactjs

我从React.js开始,我想做一个简单的表单,但在文档中我找到了两种方法.

第一种是使用参考文献:

var CommentForm = React.createClass({
  handleSubmit: function(e) {
    e.preventDefault();
    var author = React.findDOMNode(this.refs.author).value.trim();
    var text = React.findDOMNode(this.refs.text).value.trim();
    if (!text || !author) {
      return;
    }
    // TODO: send request to the server
    React.findDOMNode(this.refs.author).value = '';
    React.findDOMNode(this.refs.text).value = '';
    return;
  },
  render: function() {
    return (
      <form className="commentForm" onSubmit={this.handleSubmit}>
        <input type="text" placeholder="Your name" ref="author" />
        <input type="text" placeholder="Say something..." ref="text" />
        <input type="submit" value="Post" />
      </form>
    );
  }
});
Run Code Online (Sandbox Code Playgroud)

第二个是使用状态的阵营部件内部:

var TodoTextInput = React.createClass({
  getInitialState: function() {
    return {
      value: this.props.value || ''
    };
  },

  render: function() /*object*/ {
    return (
      <input className={this.props.className}
      id={this.props.id}
      placeholder={this.props.placeholder}
      onBlur={this._save}
      value={this.state.value}
      />
    );
  },

  _save: function() {
    this.props.onSave(this.state.value);
    this.setState({value: ''
  });
});
Run Code Online (Sandbox Code Playgroud)

如果有的话,我看不出这两种选择的利弊.谢谢.

Bri*_*and 137

简短版本:避免参考.


它们对可维护性不利,并且失去了WYSIWYG模型渲染提供的许多简单性.

你有一张表格.您需要添加一个重置表单的按钮.

  • 裁判:
    • 操纵DOM
    • render描述了3分钟前表单的外观
    • 的setState
    • render描述了表单的外观

输入中有CCV编号字段,应用程序中有一些其他字段是数字.现在您需要强制用户只输入数字.

  • 裁判:
    • 添加一个onChange处理程序(我们不是使用refs来避免这种情况吗?)
    • 如果它不是数字,则在onChange中操作dom
    • 你已经有了一个onChange处理程序
    • 添加一个if语句,如果它无效,则不执行任何操作
    • 只有在它产生不同结果时才会调用render

呃,没关系,PM希望我们只是做一个红色的盒子阴影,如果它无效的话.

  • 裁判:
    • make onChange handler只需调用forceUpdate或者什么?
    • 根据......做渲染输出?
    • 我们在哪里获得要在渲染中验证的值?
    • 手动操作元素的className dom属性?
    • 我迷路了
    • 重写没有refs?
    • 如果我们已经安装,则从渲染中的dom读取否则假设有效?
  • 州:
    • 删除if语句
    • 根据this.state进行渲染验证

我们需要将控制权交还给父母.数据现在是道具,我们需要对变化作出反应.

  • 裁判:
    • 实现componentDidMount,componentWillUpdate和componentDidUpdate
    • 手动区分以前的道具
    • 用最小的变化来操纵dom
    • 嘿!我们正在实施反应......
    • 还有更多,但我的手指受伤了
  • 州:
    • sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js

人们认为refs比保持状态更"容易".这可能在前20分钟都是如此,在我之后的经历中并非如此.把你的自己放在一个位置说"是的,我会在5分钟内完成它",而不是"当然,我只会重写一些组件".

  • 你能解释一下sed -e's/this.state/this.props /'s/handleChange/onChange /'-i form.js吗? (3认同)
  • 不确定我是否是唯一一个发现你的答案有点令人困惑的人.你能展示一些代码样本,让你的观点更清晰吗? (3认同)
  • 在屏幕上有 50 多个输入,在任何状态更改时渲染每个输入都是不可取的。将每个“输入”字段组件化,其中每个字段都保持自己的状态是理想的。在某些时候,我们确实需要用一些更大的模型来协调这些不同的独立状态。也许我们有一个计时器的自动保存,或者我们只是保存在 `componentWillUnmount` 上。这是我发现 `refs` 理想的地方,在协调过程中,我们从每个 `ref` 中提取 `state` 值,没有一个是更明智的。我同意在大多数情况下 `state` 是答案,但是对于大量的 `inputs`,使用适当的 `refs` 模式是一种性能优势 (2认同)

Tyl*_*nis 98

我见过一些人引用上面的答案作为"从不使用refs"的理由,我想给我(以及其他一些我说过的React开发者)意见.

在谈论将它们用于组件实例时,"不使用refs"情绪是正确的.意思是,您不应该使用refs来获取组件实例并在其上调用方法.这是使用refs的错误方法,当refs快速向南移动时.

使用refs的正确(也是非常有用的)方法是当你使用它们从DOM中获取一些值时.例如,如果你有一个输入字段将ref附加到该输入,那么稍后通过ref获取值就可以了.如果没有这种方式,您需要经过一个相当精心设计的过程,以使您的输入字段与您的本地状态或助焊剂存储保持同步 - 这似乎是不必要的.

  • 你的最后一段很有道理,但你可以澄清你的第二段吗?抓取组件实例并调用一个被认为不正确的方法的具体示例是什么? (3认同)
  • 我同意这一点.我使用refs除非/直到我需要验证或操纵字段的值.如果我确实需要以编程方式验证更改或更改值,那么我使用状态. (2认同)
  • 我完全同意。在我看来,接受的答案太模糊了。 (2认同)

Kap*_*har 9

这个帖子很旧了。

我就这方面的一个案例分享我的一点经验。

我正在研究一个包含大量“动态”输入和大量缓存数据的大型组件(414 行)。(我不是一个人在页面上工作,我的感觉告诉我代码的结构可能可以更好地拆分,但这不是重点(好吧,它可能是但我正在处理它)

我首先使用 state 来处理输入的值:

  const [inputsValues, setInputsValues] = useState([])
  const setInputValue = (id, value) => {
    const arr = [...inputsValues]
    arr[id] = value
    setInputsValues(arr)
  }
Run Code Online (Sandbox Code Playgroud)

当然在输入中:

value={inputsValues[id] || ''}
onChange={event => setInputValue(id, event.target.value)}
Run Code Online (Sandbox Code Playgroud)

渲染太重,输入变化像****一样断断续续(不要试图按住键,文本只会在暂停后出现)

我确信我可以使用 refs 来避免这种情况。

最终是这样的:

  const inputsRef = useRef([])
Run Code Online (Sandbox Code Playgroud)

并在输入中:

ref={input => (inputsRef.current[id] = input)}
Run Code Online (Sandbox Code Playgroud)

[在我的情况下,输入是 Material-UI TextField 所以它是:

inputRef={input => (inputsRef.current[id] = input)}
Run Code Online (Sandbox Code Playgroud)

]

多亏了这一点,没有重新渲染,输入流畅,功能以相同的方式工作。它将节省周期和计算,因此也节省能源。为地球做这件事 x)

我的结论是:输入值的 useRef 甚至可能是需要的。


Lyu*_*mir 6

TL; DR一般来说,refs违反React的声明性哲学,所以你应该将它们作为最后的手段.state / props尽可能使用.


要了解你使用refsvs的位置state / props,让我们看一下React遵循的一些设计原则.

关于Per React的文档refs

避免使用refs来做任何可以声明性地完成的事情.

Per React关于Escape Hatches的设计原则

如果某些对构建应用程序有用的模式难以以声明方式表达,我们将为其提供必要的API.(他们在这里链接到refs)

这意味着React的团队建议避免refs和使用state / props任何可以以被动/声明方式完成的事情.

@Tyler McGinnis提供了一个非常好的答案,并说明了这一点

使用refs的正确(非常有用)方法是当你使用它们从DOM中获取一些值时...

虽然你可以做到这一点,但你将会反对React的理念.如果你在输入中有价值,那肯定是来自state / props.为了保持代码的一致性和可预测性,您也应该坚持使用state / props.我承认refs有时会为您提供更快速的解决方案,因此如果您进行概念验证,则可以接受快速和脏污.

这给我们留下了几个具体的使用情况进行refs

管理焦点,文本选择或媒体播放.触发势在必行的动画.与第三方DOM库集成.