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

时间:2015-04-07 23:31:18

标签: reactjs

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

first one正在使用参考

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>
    );
  }
});

second one在React组件中使用状态

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: ''
  });
});

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

4 个答案:

答案 0 :(得分:132)

简短版本:避免参考。


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

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

  • 参:
    • 操纵DOM
    • render描述了3分钟前表单的外观
  • 状态
    • 的setState
    • render描述了表单的外观

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

  • 参:
    • 添加一个onChange处理程序(我们不使用ref来避免这种情况吗?)
    • 在onChange中操作dom,如果它不是数字
  • 状态
    • 你已经有一个onChange处理程序
    • 添加if语句,如果它无效则无效
    • 只有在生成不同结果的情况下才会调用它
呃,没关系,PM要求我们只是做一个红框阴影,如果它无效。

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

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

  • 参:
    • 实现componentDidMount,componentWillUpdate和componentDidUpdate
    • 手动区分以前的道具
    • 使用最小的更改集来操作dom
    • 哎!我们正在实施反应......
    • 还有更多,但我的手指受伤了
  • 状态:
    • sed -e 's/this.state/this.props/' 's/handleChange/onChange/' -i form.js

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

答案 1 :(得分:97)

我已经看到一些人引用上述答案作为一个理由,从来没有使用过refs&#34;我想给我(以及其他一些我已经说过的React开发者)意见。

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

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

2019年编辑:你好朋友的未来。除了我几年前提到的^,使用React Hooks,refs也是一种很好的方式来跟踪渲染之间的数据,并且不仅限于抓取DOM节点。

答案 2 :(得分:5)

TL; DR 一般来说,refs违反了React的declarative philosophy,因此您应该将它们作为最后的手段。尽可能使用state / props

要了解您使用refsstate / props的位置,让我们看一下React遵循的一些设计原则。

Per React documentation关于refs

  

避免将refs用于以声明方式完成的任何事情。

Per React关于Escape Hatches

的设计原则
  

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

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

@Tyler McGinnis提供了一个非常好的answer,并说明

  

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

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

这为refs

留下了几个concrete use cases
  

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

答案 3 :(得分:0)

此帖子很旧。

在这件事上,我将分享我的一点经验。

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

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

  const [inputsValues, setInputsValues] = useState([])
  const setInputValue = (id, value) => {
    const arr = [...inputsValues]
    arr[id] = value
    setInputsValues(arr)
  }

当然还有输入:

value={inputsValues[id] || ''}
onChange={event => setInputValue(id, event.target.value)}

渲染是如此之重,以至于输入的变化令人讨厌(****(不要试图按住键,文本只会在暂停后出现)

我确定我可以使用裁判避免这种情况。

像这样结束:

  const inputsRef = useRef([])

和输入内容:

ref={input => (inputsRef.current[id] = input)}

[ 就我而言,输入是Material-UI TextField,所以它是:

inputRef={input => (inputsRef.current[id] = input)}

]

感谢这一点,没有重新渲染,输入很流畅,功能相同。它将节省周期和计算,因此也节省了能源。为地球x)

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