2017-07-03 147 views
0

案例: 這是我的Swipper組件,其中我創建並呈現導致HomeScreen的Onboarding屏幕的所有邏輯。我正在嘗試添加導航到它,並得到了一些錯誤,我不明白。在使用反應原生Onbording之後導航到新頁面

預期結果 第三入職培訓屏幕已經顯示後,「星現在」按鈕應該導航到主屏幕。

實際結果 按3屏幕上的按鈕後,我收到以下錯誤信息: 找不到變量:導航

我運行它世博會,這裏是鏈接如果你想嘗試一下。 https://expo.io/@jfsene/onboarding

/** 
* Swiper 
* Renders a swipable set of screens passed as children, 
* pagination indicators and a button to swipe through screens 
* or to get out of the flow when the last screen is reached 
*/ 

import React, { Component } from 'react'; 
import { 
    Dimensions,  // Detects screen dimensions 
    Platform,   // Detects platform running the app 
    ScrollView,  // Handles navigation between screens 
    StyleSheet,  // CSS-like styles 
    View,    // Container component 
} from 'react-native'; 
import { StackNavigator } from 'react-navigation'; 
import Button from '../components/Button'; 
import HomeScreen from "../screens/HomeScreen"; 
import Screens from "../screens/Screens"; 

const App = StackNavigator({ 
    Home: { screen: HomeScreen }, 
}); 

// Detect screen width and height 
const { width, height } = Dimensions.get('window'); 

export default class OnboardingScreens extends Component { 

    // Props for ScrollView component 
    static defaultProps = { 
    // Arrange screens horizontally 
    horizontal: true, 
    // Scroll exactly to the next screen, instead of continous scrolling 
    pagingEnabled: true, 
    // Hide all scroll indicators 
    showsHorizontalScrollIndicator: false, 
    showsVerticalScrollIndicator: false, 
    // Do not bounce when the end is reached 
    bounces: false, 
    // Do not scroll to top when the status bar is tapped 
    scrollsToTop: false, 
    // Remove offscreen child views 
    removeClippedSubviews: true, 
    // Do not adjust content behind nav-, tab- or toolbars automatically 
    automaticallyAdjustContentInsets: false, 
    // Fisrt is screen is active 
    index: 0 
    }; 

    state = this.initState(this.props); 

    /** 
    * Initialize the state 
    */ 
    initState(props) { 

    // Get the total number of slides passed as children 
    const total = props.children ? props.children.length || 1 : 0, 
     // Current index 
     index = total > 1 ? Math.min(props.index, total - 1) : 0, 
     // Current offset 
     offset = width * index; 

    const state = { 
     total, 
     index, 
     offset, 
     width, 
     height, 
    }; 

    // Component internals as a class property, 
    // and not state to avoid component re-renders when updated 
    this.internals = { 
     isScrolling: false, 
     offset 
    }; 

    return state; 
    } 

    /** 
    * Scroll begin handler 
    * @param {object} e native event 
    */ 
    onScrollBegin = e => { 
    // Update internal isScrolling state 
    this.internals.isScrolling = true; 
    } 

    /** 
    * Scroll end handler 
    * @param {object} e native event 
    */ 
    onScrollEnd = e => { 
    // Update internal isScrolling state 
    this.internals.isScrolling = false; 

    // Update index 
    this.updateIndex(e.nativeEvent.contentOffset 
     ? e.nativeEvent.contentOffset.x 
     // When scrolled with .scrollTo() on Android there is no contentOffset 
     : e.nativeEvent.position * this.state.width 
    ); 
    } 

    /* 
    * Drag end handler 
    * @param {object} e native event 
    */ 
    onScrollEndDrag = e => { 
    const { contentOffset: { x: newOffset } } = e.nativeEvent, 
     { children } = this.props, 
     { index } = this.state, 
     { offset } = this.internals; 

    // Update internal isScrolling state 
    // if swiped right on the last slide 
    // or left on the first one 
    if (offset === newOffset && 
     (index === 0 || index === children.length - 1)) { 
     this.internals.isScrolling = false; 
    } 
    } 

    /** 
    * Update index after scroll 
    * @param {object} offset content offset 
    */ 
    updateIndex = (offset) => { 
    const state = this.state, 
     diff = offset - this.internals.offset, 
     step = state.width; 
    let index = state.index; 

    // Do nothing if offset didn't change 
    if (!diff) { 
     return; 
    } 

    // Make sure index is always an integer 
    index = parseInt(index + Math.round(diff/step), 10); 

    // Update internal offset 
    this.internals.offset = offset; 
    // Update index in the state 
    this.setState({ 
     index 
    }); 
    } 

    /** 
    * Swipe one slide forward 
    */ 

    navigate =() => { 
    const { navigate } = this.props.navigation; 
    return; 
    } 
    swipe =() => { 
    // Ignore if already scrolling or if there is less than 2 slides 
    if (this.internals.isScrolling || this.state.total < 2) { 
     return; 
    } 

    const state = this.state, 
     diff = this.state.index + 1, 
     x = diff * state.width, 
     y = 0; 

    // Call scrollTo on scrollView component to perform the swipe 
    this.scrollView && this.scrollView.scrollTo({ x, y, animated: true }); 

    // Update internal scroll state 
    this.internals.isScrolling = true; 

    // Trigger onScrollEnd manually on android 
    if (Platform.OS === 'android') { 
     setImmediate(() => { 
     this.onScrollEnd({ 
      nativeEvent: { 
      position: diff 
      } 
     }); 
     }); 
    } 
    } 

    /** 
    * Render ScrollView component 
    * @param {array} slides to swipe through 
    */ 
    renderScrollView = pages => { 
    return (
     <ScrollView ref={component => { this.scrollView = component; }} 
     {...this.props} 
     contentContainerStyle={[styles.wrapper, this.props.style]} 
     onScrollBeginDrag={this.onScrollBegin} 
     onMomentumScrollEnd={this.onScrollEnd} 
     onScrollEndDrag={this.onScrollEndDrag} 
     > 
     {pages.map((page, i) => 
      // Render each slide inside a View 
      <View style={[styles.fullScreen, styles.slide]} key={i}> 
      {page} 
      </View> 
     )} 
     </ScrollView> 
    ); 
    } 

    /** 
    * Render pagination indicators 
    */ 
    renderPagination =() => { 
    if (this.state.total <= 1) { 
     return null; 
    } 

    const ActiveDot = <View style={[styles.dot, styles.activeDot]} />, 
     Dot = <View style={styles.dot} />; 

    let dots = []; 

    for (let key = 0; key < this.state.total; key++) { 
     dots.push(key === this.state.index 
     // Active dot 
     ? React.cloneElement(ActiveDot, { key }) 
     // Other dots 
     : React.cloneElement(Dot, { key }) 
    ); 
    } 

    return (
     <View 
     pointerEvents="none" 
     style={[styles.pagination, styles.fullScreen]} 
     > 
     {dots} 
     </View> 
    ); 
    } 

    /** 
    * Render Continue or Done button 
    */ 
    renderButton =() => { 
    const lastScreen = this.state.index === this.state.total - 1; 
    return (
     <View pointerEvents="box-none" style={[styles.buttonWrapper, styles.fullScreen]}> 
     {lastScreen 
      // Show this button on the last screen 
      // TODO: Add a handler that would send a user to your app after onboarding is complete 
      ? <Button text="Start Now" onPress={() => navigate('Home')} /> 
      // Or this one otherwise 
      : <Button text="Continue" onPress={() => this.swipe()} /> 
     } 
     </View> 
    ); 
    } 

    /** 
    * Render the component 
    */ 

    render = ({ children } = this.props) => { 
    return (
     <View style={[styles.container, styles.fullScreen]}> 
     {/* Render screens */} 
     {this.renderScrollView(children)} 
     {/* Render pagination */} 
     {this.renderPagination()} 
     {/* Render Continue or Done button */} 
     {this.renderButton()} 
     </View> 
    ); 
    } 
} 

const styles = StyleSheet.create({ 
    // Set width and height to the screen size 
    fullScreen: { 
    width: width, 
    height: height 
    }, 
    // Main container 
    container: { 
    backgroundColor: 'transparent', 
    position: 'relative' 
    }, 
    // Slide 
    slide: { 
    backgroundColor: 'transparent' 
    }, 
    // Pagination indicators 
    pagination: { 
    position: 'absolute', 
    bottom: 110, 
    left: 0, 
    right: 0, 
    flex: 1, 
    flexDirection: 'row', 
    justifyContent: 'center', 
    alignItems: 'flex-end', 
    backgroundColor: 'transparent' 
    }, 
    // Pagination dot 
    dot: { 
    backgroundColor: 'rgba(0,0,0,.25)', 
    width: 8, 
    height: 8, 
    borderRadius: 4, 
    marginLeft: 3, 
    marginRight: 3, 
    marginTop: 3, 
    marginBottom: 3 
    }, 
    // Active dot 
    activeDot: { 
    backgroundColor: '#FFFFFF', 
    }, 
    // Button wrapper 
    buttonWrapper: { 
    backgroundColor: 'transparent', 
    flexDirection: 'column', 
    position: 'absolute', 
    bottom: 0, 
    left: 0, 
    flex: 1, 
    paddingHorizontal: 10, 
    paddingVertical: 40, 
    justifyContent: 'flex-end', 
    alignItems: 'center' 
    }, 
}); 
+0

請從您的代碼中顯示更多StackNavigator以查看您的導航結構。 –

回答

-1

您需要添加一個道具導航

/** 
 
* Swiper 
 
* Renders a swipable set of screens passed as children, 
 
* pagination indicators and a button to swipe through screens 
 
* or to get out of the flow when the last screen is reached 
 
*/ 
 

 
import React, { 
 
    Component 
 
} from 'react'; 
 
import { 
 
    Dimensions, // Detects screen dimensions 
 
    Platform, // Detects platform running the app 
 
    ScrollView, // Handles navigation between screens 
 
    StyleSheet, // CSS-like styles 
 
    View, // Container component 
 
} from 'react-native'; 
 
import PropTypes from 'prop-types'; 
 
import Button from './Button'; 
 

 

 
// Detect screen width and height 
 
const { 
 
    width, 
 
    height 
 
} = Dimensions.get('window'); 
 

 

 
export default class Swiper extends Component { 
 

 
    // Props for ScrollView component 
 
    static defaultProps = { 
 

 
    //Here is what you need 
 
    onPressnav: PropTypes.func.isRequired, 
 

 
    // Arrange screens horizontally 
 
    horizontal: true, 
 
    // Scroll exactly to the next screen, instead of continous scrolling 
 
    pagingEnabled: true, 
 
    // Hide all scroll indicators 
 
    showsHorizontalScrollIndicator: false, 
 
    showsVerticalScrollIndicator: false, 
 
    // Do not bounce when the end is reached 
 
    bounces: false, 
 
    // Do not scroll to top when the status bar is tapped 
 
    scrollsToTop: false, 
 
    // Remove offscreen child views 
 
    removeClippedSubviews: true, 
 
    // Do not adjust content behind nav-, tab- or toolbars automatically 
 
    automaticallyAdjustContentInsets: false, 
 
    // Fisrt is screen is active 
 
    index: 0 
 
    }; 
 

 
    state = this.initState(this.props); 
 

 
    /** 
 
    * Initialize the state 
 
    */ 
 
    initState(props) { 
 

 
    //const {goBack} = this.props.navigation; 
 
    // Get the total number of slides passed as children 
 
    const total = props.children ? props.children.length || 1 : 0, 
 
     // Current index 
 
     index = total > 1 ? Math.min(props.index, total - 1) : 0, 
 
     // Current offset 
 
     offset = width * index; 
 

 

 

 
    const state = { 
 
     total, 
 
     index, 
 
     offset, 
 
     width, 
 
     height, 
 
    }; 
 

 
    // Component internals as a class property, 
 
    // and not state to avoid component re-renders when updated 
 
    this.internals = { 
 
     isScrolling: false, 
 
     offset 
 
    }; 
 

 
    return state; 
 
    } 
 

 
    /** 
 
    * Scroll begin handler 
 
    * @param {object} e native event 
 
    */ 
 
    onScrollBegin = e => { 
 
    // Update internal isScrolling state 
 
    this.internals.isScrolling = true; 
 
    } 
 

 
    /** 
 
    * Scroll end handler 
 
    * @param {object} e native event 
 
    */ 
 
    onScrollEnd = e => { 
 
    // Update internal isScrolling state 
 
    this.internals.isScrolling = false; 
 

 
    // Update index 
 
    this.updateIndex(e.nativeEvent.contentOffset ? 
 
     e.nativeEvent.contentOffset.x 
 
     // When scrolled with .scrollTo() on Android there is no contentOffset 
 
     : 
 
     e.nativeEvent.position * this.state.width 
 
    ); 
 
    } 
 

 
    /* 
 
    * Drag end handler 
 
    * @param {object} e native event 
 
    */ 
 
    onScrollEndDrag = e => { 
 
    const { 
 
     contentOffset: { 
 
     x: newOffset 
 
     } 
 
    } = e.nativeEvent, { 
 
     children 
 
    } = this.props, { 
 
     index 
 
    } = this.state, { 
 
     offset 
 
    } = this.internals; 
 

 
    // Update internal isScrolling state 
 
    // if swiped right on the last slide 
 
    // or left on the first one 
 
    if (offset === newOffset && 
 
     (index === 0 || index === children.length - 1)) { 
 
     this.internals.isScrolling = false; 
 
    } 
 
    } 
 

 
    /** 
 
    * Update index after scroll 
 
    * @param {object} offset content offset 
 
    */ 
 
    updateIndex = (offset) => { 
 
    const state = this.state, 
 
     diff = offset - this.internals.offset, 
 
     step = state.width; 
 
    let index = state.index; 
 

 
    // Do nothing if offset didn't change 
 
    if (!diff) { 
 
     return; 
 
    } 
 

 
    // Make sure index is always an integer 
 
    index = parseInt(index + Math.round(diff/step), 10); 
 

 
    // Update internal offset 
 
    this.internals.offset = offset; 
 
    // Update index in the state 
 
    this.setState({ 
 
     index 
 
    }); 
 
    } 
 

 
    navigatet =() => { 
 
    console.log('This has been Clicked'); 
 

 
    } 
 

 
    /** 
 
    * Swipe one slide forward 
 
    */ 
 
    swipe =() => { 
 
    // Ignore if already scrolling or if there is less than 2 slides 
 
    if (this.internals.isScrolling || this.state.total < 2) { 
 
     return; 
 
    } 
 

 
    const state = this.state, 
 
     diff = this.state.index + 1, 
 
     x = diff * state.width, 
 
     y = 0; 
 

 
    // Call scrollTo on scrollView component to perform the swipe 
 
    this.scrollView && this.scrollView.scrollTo({ 
 
     x, 
 
     y, 
 
     animated: true 
 
    }); 
 

 
    // Update internal scroll state 
 
    this.internals.isScrolling = true; 
 

 
    // Trigger onScrollEnd manually on android 
 
    if (Platform.OS === 'android') { 
 
     setImmediate(() => { 
 
     this.onScrollEnd({ 
 
      nativeEvent: { 
 
      position: diff 
 
      } 
 
     }); 
 
     }); 
 
    } 
 
    } 
 

 
    /** 
 
    * Render ScrollView component 
 
    * @param {array} slides to swipe through 
 
    */ 
 
    renderScrollView = pages => { 
 
    return (< 
 
     ScrollView ref = { 
 
     component => { 
 
      this.scrollView = component; 
 
     } 
 
     } { ...this.props 
 
     } 
 
     contentContainerStyle = { 
 
     [styles.wrapper, this.props.style] 
 
     } 
 
     onScrollBeginDrag = { 
 
     this.onScrollBegin 
 
     } 
 
     onMomentumScrollEnd = { 
 
     this.onScrollEnd 
 
     } 
 
     onScrollEndDrag = { 
 
     this.onScrollEndDrag 
 
     } > 
 
     { 
 
     pages.map((page, i) => 
 
      // Render each slide inside a View 
 
      < 
 
      View style = { 
 
      [styles.fullScreen, styles.slide] 
 
      } 
 
      key = { 
 
      i 
 
      } > { 
 
      page 
 
      } < 
 
      /View> 
 
     ) 
 
     } < 
 
     /ScrollView> 
 
    ); 
 
    } 
 

 
    /** 
 
    * Render pagination indicators 
 
    */ 
 
    renderPagination =() => { 
 
    if (this.state.total <= 1) { 
 
     return null; 
 
    } 
 

 
    const ActiveDot = < View style = { 
 
     [styles.dot, styles.activeDot] 
 
    } 
 
    />, 
 
    Dot = < View style = { 
 
     styles.dot 
 
    } 
 
    />; 
 

 
    let dots = []; 
 

 
    for (let key = 0; key < this.state.total; key++) { 
 
     dots.push(key === this.state.index 
 
     // Active dot 
 
     ? 
 
     React.cloneElement(ActiveDot, { 
 
      key 
 
     }) 
 
     // Other dots 
 
     : 
 
     React.cloneElement(Dot, { 
 
      key 
 
     }) 
 
    ); 
 
    } 
 

 
    return (< 
 
     View pointerEvents = "none" 
 
     style = { 
 
     [styles.pagination, styles.fullScreen] 
 
     } > 
 
     { 
 
     dots 
 
     } < 
 
     /View> 
 
    ); 
 
    } 
 

 
    /** 
 
    * Render Continue or Done button 
 
    */ 
 
    renderButton =() => { 
 
    navigation = this.props.navigation 
 
    const lastScreen = this.state.index === this.state.total - 1; 
 
    return (< 
 
     View pointerEvents = "box-none" 
 
     style = { 
 
     [styles.buttonWrapper, styles.fullScreen] 
 
     } > { 
 
     lastScreen 
 
     // Show this button on the last screen 
 
     // TODO: Add a handler that would send a user to your app after onboarding is complete 
 
     ? 
 
     < Button text = "Start Now" 
 
     onPress = { 
 
      this.props.onPressnav 
 
     } 
 
     /> 
 
     // Or this one otherwise 
 
     : 
 
      < Button text = "Continue" 
 
     onPress = { 
 
     () => this.swipe() 
 
     } 
 
     /> 
 
     } < 
 
     /View> 
 
    ); 
 
    } 
 

 
    /** 
 
    * Render the component 
 
    */ 
 
    render = ({ 
 
    children 
 
    } = this.props) => { 
 

 
    return (< 
 
     View style = { 
 
     [styles.container, styles.fullScreen] 
 
     } > { /* Render screens */ } { 
 
     this.renderScrollView(children) 
 
     } { /* Render pagination */ } { 
 
     this.renderPagination() 
 
     } { /* Render Continue or Done button */ } { 
 
     this.renderButton() 
 
     } < 
 
     /View> 
 
    ); 
 
    } 
 
} 
 

 
const styles = StyleSheet.create({ 
 
    // Set width and height to the screen size 
 
    fullScreen: { 
 
    width: width, 
 
    height: height 
 
    }, 
 
    // Main container 
 
    container: { 
 
    backgroundColor: 'transparent', 
 
    position: 'relative' 
 
    }, 
 
    // Slide 
 
    slide: { 
 
    backgroundColor: 'transparent' 
 
    }, 
 
    // Pagination indicators 
 
    pagination: { 
 
    position: 'absolute', 
 
    bottom: 110, 
 
    left: 0, 
 
    right: 0, 
 
    flex: 1, 
 
    flexDirection: 'row', 
 
    justifyContent: 'center', 
 
    alignItems: 'flex-end', 
 
    backgroundColor: 'transparent' 
 
    }, 
 
    // Pagination dot 
 
    dot: { 
 
    backgroundColor: 'rgba(0,0,0,.25)', 
 
    width: 8, 
 
    height: 8, 
 
    borderRadius: 4, 
 
    marginLeft: 3, 
 
    marginRight: 3, 
 
    marginTop: 3, 
 
    marginBottom: 3 
 
    }, 
 
    // Active dot 
 
    activeDot: { 
 
    backgroundColor: '#5FD7F4', 
 
    }, 
 
    // Button wrapper 
 
    buttonWrapper: { 
 
    backgroundColor: 'transparent', 
 
    flexDirection: 'column', 
 
    position: 'absolute', 
 
    bottom: 0, 
 
    left: 0, 
 
    flex: 1, 
 
    paddingHorizontal: 10, 
 
    paddingVertical: 40, 
 
    justifyContent: 'flex-end', 
 
    alignItems: 'center' 
 
    }, 
 
});

+1

這並沒有真正回答這個問題。如果您有不同的問題,可以通過單擊[提問](https://stackoverflow.com/questions/ask)來提問。您可以[添加賞金](https://stackoverflow.com/help/privileges/set-bounties)在您擁有足夠的[聲譽](https://stackoverflow.com/help/)後吸引更多關注此問題什麼聲譽)。 - [來自評論](/ review/low-quality-posts/18484928) – rzelek

0

如果要導航到主屏幕OnboardingScreens,OnboardingScreens應StackNavigator被添加。

相關問題