2016-08-11 3 views
0

Я совершенно новый, чтобы реагировать в Метеор.ReactiveVar не повторное рендеринг Реактивный компонент

TL; DR: В моем контейнере данных изменение значения моего ReactiveVar не отменяет моего представления.

У меня этот код:

import React, { Component, PropTypes } from 'react'; 
import ReactDOM from 'react-dom'; 
import { Meteor } from 'meteor/meteor'; 
import { createContainer } from 'meteor/react-meteor-data'; 

// Mail composer - interface for generating enews 
class MailComposer extends Component { 
    constructor(props) { 
    super(props); 
    } 

    handleSubmit(event) { 
    event.preventDefault(); 

    const text = this.refs.mailText.value.trim(), 
      title = this.refs.mailTitle.value.trim(), 
      rcpts = this.refs.mailRecpts.value.trim(); 

    console.log(text, title, rcpts); 

    if (text && title && rcpts) { 
     // ... 
     this.props.hasTestedIt.set(true); 
    } else { 
     // ... 
    } 
    } 

    componentDidMount() { 
    console.log(this); 
    $(this.refs.textArea).autosize(); 
    } 

    getBtnText() { 
    return (this.props.hasTestedIt.get() ? "Send it" : "Test it"); 
    } 

    render() { 
    let self = this; 
    Tracker.autorun(function(){ 
     console.log(self.props.hasTestedIt.get()); 
    }); 

    return (
     <div className="panel panel-default panel-primary"> 
     <div className="panel-heading"> 
      <h3 className="panel-title">Mail composer</h3> 
     </div> 
     <div className="panel-body"> 
      <form className="form-group" onSubmit={this.handleSubmit.bind(this)}> 
      <div className="input-group"> 
       <span className="input-group-addon" id="basic-addon1">Title</span> 
       <input type="text" className="form-control" ref="mailTitle" /> 
      </div> 
      <br/> 
      <label htmlFor="js-recipients">Recipients:</label> 
      <select className="form-control" width="width: initial;" id="js-recipients" ref="mailRecpts"> 
       <option>Admins</option> 
       <option>All</option> 
      </select> 
      <br/> 
      <label htmlFor="comment">Text:</label> 
      <textarea className="form-control" rows="5" ref="mailText"></textarea> 
      <br/> 
      <button className="btn btn-primary" type="submit"> 
       {this.getBtnText()} 
      </button> 
      </form> 
     </div> 
     </div> 
    ); 
    } 
} 

MailComposer.propTypes = { 
    hasTestedIt: PropTypes.object.isRequired 
}; 

export default createContainer(() => { 
    return { 
    hasTestedIt: new ReactiveVar(false) 
    }; 
}, MailComposer);` 

Но когда я поставил свою ReactiveVar опору в моей представить обработчик, текст, возвращаемый методом getBtnText в кнопке не меняется. Я попытался поместить тройку прямо в HTML, но я получил тот же результат. var правильно настроен на true, так как автозапуск корректно регистрирует меня.

В другом компоненте, из которого этот один был скопирован, я правильно повторно вызывать компонент, но с использованием .fetch() на find к карте возвращаемый массив в renderTasks метод, который вынести список новых компонентов.

Что я пропущу, пожалуйста? И как я могу это исправить?

Большое спасибо!

ответ

2

Компонент не обновляется, потому что пройденный hasTestedIt опорный пункт не изменяется сам. Это значение, которое оно сохраняет, изменилось.

Посмотрите на интересующую вас ценность.

// Declare the reactive source somewhere appropriately. 
const hasTestedIt = new ReactiveVar(false); 

// Watch its value instead. 
export default createContainer(() => { 
    return { 
    hasTestedIt: hasTestedIt.get() 
    }; 
}, MailComposer);` 

Обратите внимание, что теперь значение, переданное в MailComposer, не ReactiveVar что можно ссылаться больше обновить значение. Как мы обновляем его в этом случае?

Один из самых простых способов - передать hasTestedIt, как и раньше, хотя это не было моей личной рекомендацией.

// Watch its value instead. 
export default createContainer(() => { 
    return { 
    // Reactive source that triggers re-rendering. 
    valueOfHasTestedIt: hasTestedIt.get(), 
    // Provided for the contained component to reference to set new values. 
    // Leaving this alone doesn't trigger re-rendering! 
    hasTested 
    }; 
}, MailComposer); 

Это не элегантный ИМО. Другим является передача функции обратного вызова в MailComposer, которая может использоваться для обновления значения.

const updateHasTestedIt = (value) => hasTestedIt.set(value); 

// Watch its value instead. 
export default createContainer(() => { 
    return { 
    hasTestedIt: hasTestedIt.get(), 
    updateHasTestedIt, 
    }; 
}, MailComposer); 

class MailComposer extends Component { 
    ... 
    handleSubmit(event) { 
    ... 
    this.props.updateHasTestedIt(true); 
    ... 
    } 
    ... 
}; 

На этот раз лучше.

Возможно разработать больше, но это действительно зависит от вашего предпочтения для вашего самого приложения. Вы и только вы можете принять дизайнерское решение.

+0

Когда вы хотите передать 'hasTestedIt' так же, как и раньше, вы хотите передать непосредственно значение в контейнере? Если это так, изменение значения все равно может привести к перезапуску, хотя это не из реактивногоVar? Помогите оценить, спасибо. –

+1

@ Давид Панарт, да. Если возвращаемое значение 'createContainer' не будет изменено в неглубоком сравнении, повторный рендеринг не будет инициирован, несмотря на то, что' hasTestedIt' является реактивным источником. – Season