2016-08-11 242 views
0

我對流星中的React很陌生。ReactiveVar無法重新渲染React組件

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,因爲自動運行可以正確記錄我所做的更改。

在另一組分,從中這一個已被複制,我做正確重新呈現該組件,但使用上的一個find.fetch()renderTasks方法,其呈現新組件列表返回的數組映射。

我錯過了什麼?我怎麼修復它?

非常感謝!

回答

2

組件不會更新,因爲傳遞的hasTestedIt prop本身沒有更改。它所持有的價值已經發生了變化。

請注意您實際感興趣的值。

// 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'以及之前,你的意思是直接傳遞容器中的值?如果是這樣,更改值仍然可以開始重新渲染,儘管它不是來自reactiveVar? 非常感謝,謝謝。 –

+1

@David Panart,是的。如果'createContainer'的返回值在淺比較中沒有改變,即使'hasTestedIt'是一個被動源,也不會觸發重新呈現。 – Season