2015-11-23 10 views
7

मैं प्रतिक्रिया मूल में एक अनंत स्क्रॉल को लागू करने की कोशिश कर रहा हूं। नीचे घटक का स्रोत है:प्रतिक्रिया मूल सूची देखें - rowHasChanged आग नहीं है

var React = require('react-native'); 
var server = require('../server'); 
var Post = require('./Post'); 
var SwipeRefreshLayoutAndroid = require('./SwipeRefreshLayout'); 
var backEvent = null; 
var lastPostId = ""; 
var isLoadingMore = false; 
var isLoadingTop = false; 
var onEndReachedActive = false; 

var { 
    StyleSheet, 
    ListView, 
    View, 
    Text, 
    Image, 
    ProgressBarAndroid, 
    BackAndroid 
} = React; 

class Stream extends React.Component { 

constructor(props) { 
    super(props); 
    this.ds = new ListView.DataSource({ 
     rowHasChanged: (row1, row2) => { 
      console.log("rowHasChenged FIRED!!"); 
      return false; 
     } 
    }); 

    this.state = { 
     dataSource: this.ds.cloneWithRows(['loader']), 
     hasStream: false, 
     posts: [] 
    }; 

} 

componentDidMount() { 

    BackAndroid.addEventListener('hardwareBackPress',() => { 
     this.props.navigator.jumpBack(); 
     return true; 
    }.bind(this)); 

    server.getStream('', '', 15).then((res) => { 

     lastPostId = res[res.length-1].m._id; 

     this.setState({ 
      posts: res, 
      hasStream: true, 
      dataSource: this.ds.cloneWithRows(res) 
     },() => onEndReachedActive = true); 
    }) 
} 

onRefresh() { 
    var posts = this.state.posts; 
    var firstPost = posts[0].m._id; 

    console.log(this.state.dataSource._rowHasChanged); 

    isLoadingTop = true; 

    server.getStream('', firstPost, 4000) 
     .then(res => { 
      console.log(posts.length); 
      posts = res.concat(posts); 
      console.log(posts.length); 
      this.setState({ 
       dataSource: this.ds.cloneWithRows(posts), 
       posts 
      },() => { 
       this.swipeRefreshLayout && this.swipeRefreshLayout.finishRefresh(); 
       isLoadingTop = false; 
      }); 
     }).catch((err) => { 
      isLoadingTop = false; 
     }) 

} 

onEndReached(event) { 

    if(!onEndReachedActive) return; 

    if(this.state.loadingMore || this.state.isLoadingTop)return; 
    isLoadingMore = true; 
    var posts = this.state.posts; 
    server.getStream(posts[posts.length-1].m._id, '', 15) 
     .then(res => { 
      console.log('received posts'); 
      posts = posts.concat(res); 
      lastPostId = posts[posts.length-1].m._id; 
      this.setState({ 
       dataSource: this.ds.cloneWithRows(posts), 
       posts 
      },()=>isLoadingMore = false); 
     }) 
} 

renderHeader() { 
    return (
     <View style={styles.header}> 
      <Text style={styles.headerText}>Header</Text> 
     </View> 
    ) 
} 

renderRow(post) { 

    if(post === 'loader') { 
     return (
      <ProgressBarAndroid 
       styleAttr="Large" 
       style={styles.spinnerBottom}/> 
     ) 
    } 

    let hasLoader = post.m._id === lastPostId; 

    let loader = hasLoader ? 
     <ProgressBarAndroid 
      styleAttr="Large" 
      style={styles.spinnerBottom}/> : null; 

    return (
     <View> 
      <Post 
       post={post}/> 
      {loader} 
     </View> 
    ) 
} 

render() { 


    return (
       <ListView 
        style={styles.mainContainer} 
        dataSource={this.state.dataSource} 
        renderRow={this.renderRow.bind(this)} 
        onEndReached={this.onEndReached.bind(this)} 
        onEndReachedThreshold={1} 
        pageSize={15} /> 
    ); 
} 
} 

समस्या यह है कि जब भी मैं संलग्न (या आगे जोड़ते) नए डेटा, DataSource की rowHasChanged विधि आग नहीं करता है। यह सिर्फ हर पंक्ति को फिर से प्रस्तुत करता है, यहां तक ​​कि कुछ भी नहीं बदला है (नए डेटा को छोड़कर)। कोई विचार क्यों विधि को छोड़ दिया गया है?

उत्तर

12

संपादित करें: दौड़ की स्थिति

मैं सिर्फ यह सोचा बाहर से बचने के लिए setState करने के लिए एक समारोह को पारित करना। यदि आपके पास एक ही समस्या है, तो उस बिंदु को चेक करें जिस पर आप अपना राज्य नए dataSource के साथ बदलते हैं। मेरा इस तरह था:

this.setState({ 
    dataSource: this.ds.cloneWithRows(posts) 
}); 

इसके बजाय आप हमेशा dataSource पहले वाली स्थिति से इस तरह का प्रयोग करना चाहिए,:

this.setState(state => ({ 
    dataSource: this.state.dataSource.cloneWithRows(posts) 
})) 

चीयर्स!

+0

क्या किसी को पता है कि यह डॉक्यू है प्रतिक्रिया मूल दस्तावेज़ों में कहीं भी mented? मुझे यह विशेष रूप से उल्लेख नहीं किया जा सकता है और यह महत्वपूर्ण लगता है ... –

+0

यदि आप राज्य को अपडेट करने के लिए वर्तमान स्थिति का उपयोग कर रहे हैं, तो आपको 'this.setState ((state) => ({dataSource: state.dataSource.cloneWithRows (पोस्ट)})); '। सेटिंग सेट एक फंक्शन एक दौड़ की स्थिति का खतरा कम कर देता है। – jtolds

+0

@jtolds संपादित, धन्यवाद! –

3

यह मेरे लिए काम करता है, उम्मीद है कि इससे मदद मिलती है। मैं एक नया डेटा स्रोत बनाया है और राज्य परिवर्तन पर यह करने के लिए अद्यतन डेटा सौंपा इस प्रकार है: `

var dataSource = new ListView.DataSource(
    {rowHasChanged: (r1, r2) => (r1 !== r2)}); 

    this.setState({ dataSource : dataSource.cloneWithRows(posts) }); 

अब, नए डेटा असाइन किया गया है और देखने को सही ढंग से प्रदान की गई है। ध्यान दें कि अब निर्दिष्ट किए गए पोस्ट सरणी को अद्यतन डेटा है। फिर भी सोच रहा है कि अगर यह करने का सबसे अच्छा तरीका है लेकिन यह काम करता है!

+0

यह उत्तर नहीं है। मूल प्रश्न में कोड, नया डेटा भी सामान्य के रूप में असाइन किया जाता है और दृश्य भी सही ढंग से प्रस्तुत किया जाता है। सवाल यह है कि क्यों नया डेटा आने पर rowHasChanged नहीं कहा जाता है। इसे पुन: उत्पन्न करने के लिए, आपको rowHasChanged में console.log डालने की आवश्यकता है और कृपया रेंडर() में एक console.log डालें। और आप पाएंगे कि इस कोड का उपयोग करके सभी पंक्तियां, कोई फर्क नहीं पड़ता कि पुराना, नया, बदले नहीं बदला गया है, सेटस्टेट कहलाए जाने के बाद फिर से प्रस्तुत किया जाएगा। राडो द्वारा सही उत्तर का उत्तर नीचे दिया गया है। –

1

मैं मानता हूँ यह लगता भावना है कि आप हमेशा पहले वाली स्थिति से डेटा स्रोत का उपयोग करना चाहिए बनाने के लिए।

फिर भी जब मैं इस तरह से setState, rowHasChanged सभी पंक्तियों के लिए कहा जाता हो जाता है, तथापि, rowHasChanged हमेशा झूठी वापस आती है और यदि कोई भी पंक्ति गाया जाता है ??? क्यूं कर?

// This is callback handler that the ListView DetailView will 
    // call when a ListView item is edited 
    onChange(waypoint: Object){ 
    console.log('Callback: rowNumber= ', waypoint.rowNumber); 
    console.log('  length(m)= ', waypoint.distance.meters); 

    var itemListChanged = this.state.itemList; 
    itemListChanged[waypoint.rowNumber-1] = waypoint; 
    this.setState({ 
      dataSource: this.state.dataSource.cloneWithRows(itemListChanged), 
    }); 
    }, 

अगर मैं इस तरह से setState, renderRow बिना शर्त बिना सभी पंक्तियों के लिए कहा जाता है कभी बुलाया जा रहा है rowHasChanged। क्या सही है?

this.setState({ 
    dataSource: ds.cloneWithRows(itemListChanged), 
}); 

ListView, डेटा स्रोत, और प्रतिक्रिया देशी एक कठिन सीखने की अवस्था सी #/C/C++ से आ रही हैं।

+0

हो सकता है कि आप अपने कन्स्ट्रक्टर, rowHasChanged फ़ंक्शन पोस्ट कर सकें। –

+0

एक अनुमान है कि आपने "मूल्य से पारित नहीं किया" है, लेकिन "संदर्भ द्वारा पारित किया गया", जिसका अर्थ है, this.state.dataSource पहले से ही उसी मान में बदल दिया गया है (जैसा कि वे एक ही राम पते पर इंगित करते हैं)। मान लीजिए कि आप एक सेब टोकरी को आवंटित करते हैं, यह सेब प्रस्तुत करता है, आप सेब निकालते हैं और एक नारंगी टोकरी में डालते हैं, आपको लगता है कि यह सेब की तुलना नारंगी से कर रहा है, लेकिन वास्तव में, आप टोकरी में चीज़ों की तुलना टोकरी के साथ कर रहे हैं। आप नारंगी के साथ संतरे की तुलना कर रहे हैं। –

+0

समाधान यह है कि आप पहले से टोकरी बी को एक सेब आवंटित करते हैं और फिर जब आप टोकरी में चीजों की तुलना करते हैं, तो टोकरी सी में नारंगी डाल दें। तुलना करने के लिए आपको 1 से अधिक टोकरी की आवश्यकता है। संक्षेप में आप एक राज्य में एक प्रोप डालते हैं, एक बार प्रोप बदलने के बाद, सेटस्टेट को कॉल करने से पहले राज्य पहले ही बदल चुका है। –

0

किसी को अब भी के साथ इस मुद्दे होने के लिए कहा जाता है rowHasChanged लेकिन अभी भी झूठी निम्नलिखित स्निपेट लौट रहे हैं

मदद कर सकता है डेटा स्रोत हमेशा की तरह की तरह आरंभ नहीं हो जाता:

let ds = new ListView.DataSource ({ 

    rowHasChanged: (a, b) => { 
    const changed = (a !== b) 
    return changed 
    } 

}) 

this.data = [] 

this.state = { 
    listDataSource: ds.cloneWithRows(this.data) 
} 

यहाँ समारोह जो होगा है एक पंक्ति अद्यतन करें

updateRow = (row, rowId, sectionId) => { 

    // make a shallow clone from the stored data array 
    let blob = this.data.concat() 

    // modify the row, since we are using the triple equal operator, we need to make sure we are giving it a new object (new ref) 
    blob[rowId] = Object.assign({}, blob[rowId], {label: blob[rowId].label + '..cape..deh'}) 

    // tell react to update the source 
    this.setState({ 
    listDataSource: this.state.listDataSource.cloneWithRows(blob) 
    },() => { 
    // we need to update our data storage here! after the state is changed 
    this.data = blob 
    }) 

} 
संबंधित मुद्दे