2016-05-26 2 views
38

В документации React они говорят:Почему ref = 'string' является "legacy"?

Реагировать также поддерживает использование строки (вместо обратного вызова) в качестве исх опоры на какой-либо компонент, хотя этот подход в основном наследие в этой точке.

https://facebook.github.io/react/docs/more-about-refs.html

Рассмотрим следующий пример:

class Foo extends Component { 
    render() { 
    return <input onClick={() => this.action()} ref={input => this._input = input} />; 
    } 
    action() { 
    console.log(this._input.value); 
    } 
} 

Почему я предпочитаю это, вместо того, чтобы:

class Foo extends Component { 
    render() { 
    return <input onClick={() => this.action()} ref='input' />; 
    } 
    action() { 
    console.log(this.refs.input.value); 
    } 
} 

?

Кажется, что гораздо более чистый и легкий второй пример.
Существуют ли риски, что метод string будет устаревшим?


NB: Я ищу «официальный» ответ на заявление в документации, я не спрашиваю о личных предпочтениях и так далее.

+1

Возможно, это связано с этим? https://facebook.github.io/react/blog/2015/02/24/streamlining-react-elements.html#pending-change-the-refs-semantics т. е. нарушение права собственности вдали от родителя? Есть и другие преимущества, но я думаю, что это были их первоначальные рассуждения, возможно? – ctrlplusb

+1

Хмм, читайте здесь: https://github.com/facebook/react/issues/3228#issuecomment-75461381 – ctrlplusb

+0

Как в сторону, я получаю ошибку перебора с первым методом. Функция стрелки не должна возвращать присвоение. – skube

ответ

34

Хотя, возможно, более простой, старый API refs может быть затруднен в некоторых случаях, например, когда используется в обратном вызове. Весь вид статического анализа - это боль со строками. API-интерфейс, основанный на обратном вызове, может делать все, что может использовать строка API, и более, только немного добавив многословие.

class Repeat extends React.Component { 
    render() { 
    return <ul> { 
     [...Array(+this.props.times)].map((_, i) => { 
     return <li key={i}> { this.props.template(i) } </li> 
     }) 
    } </ul> 
    } 
} 

class Hello extends React.Component { 
    constructor() { 
    super(); 
    this.refDict = {}; 
    } 

    render() { 
    return <Repeat times="3" template={i => <span ref= {el => this.refDict[i] = el}> Hello {i} </span>} /> 
      {/*         ^^^ Try doing this with the string API   */} 
    } 
} 

Дальнейшее обсуждение и немного более полный список возможных проблем с API на основе строки можно найти из issue #1373, где был введен апи на основе обратного вызова. Здесь я приведу список из описания проблемы:

API-интерфейс ref нарушен в нескольких аспектах.

  • Вы должны обратиться к this.refs [ 'MyName'] в виде строк, чтобы быть совместимым Closure Compiler Advanced Mode.

  • Это не допускает понятия нескольких владельцев одного экземпляра.

  • Волшебные динамические строки потенциально ломают оптимизацию в виртуальных машинах.

  • Он должен быть всегда согласованным, поскольку он синхронно разрешен. Это означает, что асинхронная пакетная обработка рендеринга вводит потенциальные ошибки.

  • В настоящее время у нас есть крючок, чтобы получить ссылки для братьев и сестер, чтобы вы могли иметь один компонент, ссылаясь на его родство как справочную ссылку. Это работает только на одном уровне. Это нарушает способность обертывания одного из них в инкапсуляции.

  • Нельзя статически печатать. Вы должны использовать его при любом использовании на языках типа TypeScript.

  • В обратном вызове, вызванном ребенком, нет способа привязать ref к правильному «владельцу». <Child renderer={index => <div ref="test">{index}</div>} /> - эта ссылка будет прикреплена, если вызывается обратный вызов, а не у текущего владельца.


Документы называют старую строку API «наследства», чтобы сделать его более ясным, что обратный вызов на основе API подход является предпочтительным, так как обсуждаются в this commit и в this PR, которые являются которые фактически помещают эти заявления в документацию в первую очередь. Также обратите внимание, что в некоторых комментариях подразумевается, что строка refs api может быть устарела в какой-то момент.

12

Первоначально Написал danabramov на https://news.ycombinator.com/edit?id=12093234

  1. Струнные рефов не компонуемы. Компонент-обертка не может «snoop» на ref для ребенка, если он уже имеет существующую строку ref. С другой стороны, обратные вызовы не имеют ни одного владельца, поэтому вы всегда можете их составлять.
  2. Строковые ссылки не работают со статическим анализом, таким как Flow. Поток не может угадать волшебство, которое делает фреймворк, чтобы строка ref появилась на this.refs, а также ее тип (который может быть другим). Обратные обратные вызовы более дружелюбны к статическому анализу.
  3. Владелец для строки ref определяется текущим исполняемым компонентом. Это означает, что при использовании обычного шаблона обратного вызова рендеринга (например, <DataTable renderRow={this.renderRow} />) неправильному компоненту будет принадлежать ref (он будет в конечном итоге на DataTable вместо вашего компонента, определяющего renderRow).
  4. String refs force Реагировать на отслеживание текущего компонента. Это проблематично, потому что он делает состояние работоспособным и, следовательно, вызывает странные ошибки, когда модуль react дублируется в комплекте.
Смежные вопросы