在 React 0.14.8 中使用 refs 时出错

Error using refs in React 0.14.8

我正在努力将我的应用程序中的一些代码提取到一个开源包中。我的应用程序和我的包都依赖于相同版本的 React,0.14.8。

自从我将代码移入包中(并进行了一些代码更改)以来,我一直无法呈现使用 refs 的组件。我已经搜索了几个小时的建议,它产生了两个基本提示:

  1. 确保 React 版本不冲突
  2. 确保带有 refs 的组件是在另一个组件的渲染方法中创建的

据我所知,我满足了这两个条件。

class RangeQuery extends React.Component {
  static propTypes = {
    header: PropTypes.object.isRequired,
    onQueryChange: PropTypes.func.isRequired
  }

  handleChange(ev) {
    const { header } = this.props

    const start = _.isEmpty(this.refs.start.value) ? null : this.refs.start.value
    const end = _.isEmpty(this.refs.end.value) ? null : this.refs.end.value

    const values = typeof(header.query.format) === 'function' ?
      [header.query.fmtValue(start), header.query.fmtValue(end)] :
      [start, end]

    this.props.onQueryChange(header.field, header.query, values)
  }

  render() {
    return (
      <div>
        <input className="form-control" type="text" ref="start" onChange={::this.handleChange} placeholder="min" />
        <input className="form-control" type="text" ref="end"   onChange={::this.handleChange} placeholder="max" />
      </div>
    )
  }
}

const components = {
  like: LikeQuery,
  eq: EqQuery,
  range: RangeQuery
}

export default class HeaderQuery extends React.Component {
  static propTypes = {
    header: PropTypes.object.isRequired,
    onQueryChange: PropTypes.func.isRequired
  }

  render() {
    const { header, onQueryChange } = this.props
    const Query = components[header.query.type] || NoQuery

    return (
      <Query header={header} query={header.query} onQueryChange={this.props.onQueryChange} />
    )
  }
}

当我尝试加载带有此组件的页面时,出现错误:

invariant.js:39 Uncaught Invariant Violation: addComponentAsRefTo(...): Only a ReactOwner can have refs. You might be adding a ref to a component that was not created inside a component's render method, or you have multiple copies of React loaded

如果我从 input 标签中删除 refs=,它就会呈现,但我显然需要这些。

我已经考虑过编写一个 reducer 来控制这些组件的状态的替代方法,但对于应该工作的东西来说,这是一项繁重的工作。

如何修复我的引用,使它们正常工作?

更新

虽然我接受了这个问题的答案,因为它允许我像我想要的那样使用 refs,但问题仍然是为什么它首先发生,调查显示最大的怀疑是多个版本的反应。据我所知,情况似乎并非如此。

sam@sam-macbook-ubuntu:~/myProject/client$ npm ls | grep react
├─┬ babel-preset-react@6.5.0
│ ├─┬ babel-plugin-transform-react-display-name@6.5.0
│ ├─┬ babel-plugin-transform-react-jsx@6.7.5
│ │ ├─┬ babel-helper-builder-react-jsx@6.7.5
│ └─┬ babel-plugin-transform-react-jsx-source@6.5.0
├─┬ react@0.14.8
├── react-addons-css-transition-group@0.14.8
├── react-addons-test-utils@0.14.8
├── react-dom@0.14.8
├─┬ react-loader@2.2.0
├─┬ react-redux@4.4.1
│ ├── hoist-non-react-statics@1.0.5
├── react-router@1.0.3
├─┬ react-select@1.0.0-beta12
│ └── react-input-autosize@0.6.10
│ ├─┬ react-json-tree@0.1.9
│ ├─┬ react-mixin@1.7.0
│ └── react-redux@3.1.2
│ └── react-lazy-cache@3.0.1

你试过类似的东西吗:

  import ReactDOM from 'react-dom'
const start = _.isEmpty(ReactDOM.findDOMNode(this.refs.start).value) ? null : ReactDOM.findDOMNode(this.refs.start).value
    const end = _.isEmpty(ReactDOM.findDOMNode(this.refs.end).value) ? null : ReactDOM.findDOMNode(this.refs.end).value

我接受了你的 class 并且你的 refs 有效 我做了这个简单的测试 :

import React, { PropTypes, Component } from 'react'
import _ from 'lodash'

export default class RangeQuery extends React.Component {


    handleChange(ev) {


        const start = _.isEmpty(this.refs.start.value) ? null : this.refs.start.value
        const end = _.isEmpty(this.refs.end.value) ? null : this.refs.end.value
        console.log("start")
        console.log(start)


        console.log("end")
        console.log(end)
    }

    render() {
        return (
            <div>
                <input className="form-control" type="text" ref="start" onChange={::this.handleChange} placeholder="min" />
                <input className="form-control" type="text" ref="end"   onChange={::this.handleChange} placeholder="max" />
            </div>
        )
    }
}

唯一的区别是我在 class 之前添加了:export default 如果有帮助请告诉我

不清楚问题出在哪里,这听起来仍然像是 React 的副本,但一种解决方法是使用函数 ref 样式,这无论如何都是未来的首选样式:

<input ref={(node) => this.startInput = node} />

然后就可以访问this.startInput.value.

这绝对有效

ReactDOM.findDOMNode(this.refs.start).value;