我想在我的react-native App中插入一个定义路线的导航。我找到了Navigate.js。不幸的是,它在我的应用中无法正常运行。指示以下错误:
Null不是对象(评估' route.component')
我在代码中找不到任何错误。我不明白为什么没有定义对象。但是,在demo它完美地运作。你能帮我么?
index.android.js:
import React, { Component } from 'react';
import {
AppRegistry, Navigator, DrawerLayoutAndroid, ScrollView, View, Text
} from 'react-native';
import Navigate from './src/utils/Navigate';
import Navigation from './src/scenes/Navigation';
import Home from './src/views/Home';
class app extends Component {
static childContextTypes = {
drawer: React.PropTypes.object,
navigator: React.PropTypes.object
};
constructor(props) {
super(props);
this.state = {
drawer: null,
navigator: null
};
}
getChildContext = () => {
return {
drawer: this.state.drawer,
navigator: this.state.navigator
}
};
setDrawer = (drawer) => {
this.setState({
drawer
});
};
setNavigator = (navigator) => {
this.setState({
navigator: new Navigate(navigator)
});
};
render() {
const { drawer, navigator } = this.state;
const navView = React.createElement(Navigation);
return (
<DrawerLayoutAndroid
drawerWidth={300}
drawerPosition={DrawerLayoutAndroid.positions.Left}
renderNavigationView={() => {
if (drawer && navigator) {
return navView;
}
return null;
}}
ref={(drawer) => { !this.state.drawer ? this.setDrawer(drawer) : null }}
>
{drawer &&
<Navigator
initialRoute={Navigate.getInitialRoute()}
navigationBar={<Toolbar onIconPress={drawer.openDrawer} />}
configureScene={() => {
return Navigator.SceneConfigs.FadeAndroid;
}}
ref={(navigator) => { !this.state.navigator ? this.setNavigator(navigator) : null }}
renderScene={(route) => {
if (this.state.navigator && route.component) {
return (
<View
style={styles.scene}
showsVerticalScrollIndicator={false}>
<route.component title={route.title} path={route.path} {...route.props} />
</View>
);
}
}}
/>
}
</DrawerLayoutAndroid>
);
}
}
AppRegistry.registerComponent('app', () => app);
const styles = {
scene: {
flex: 1,
marginTop: 56
}
};
routes.js:
export default {
home: {
initialRoute: true,
title: 'Home',
component: require('./views/Home').default,
},
hotels: {
title: 'Hotels',
component: require('./views/Hotels').default
},
}
./ src / utils / Navigate.js:
import { BackAndroid } from 'react-native';
let routes = null;
try {
routes = require('../routes').default;
} catch (e) {
}
export default class Navigate {
/**
* Gets the initial root props
* Accepts a parent route name and finds that routes props
* OR - Finds the first parent route with 'initialRoute' set to true.
* OR FINALLY - Returns the first parent route.
* @param path
* @param customRoutes
* @returns {{path: *}}
*/
static getInitialRoute = (path, customRoutes) => {
if (customRoutes) {
routes = customRoutes;
}
if (!routes) {
console.warn(`[Navigate.getInitialRoute()] No routes found. Add routes to src/routes.js.`);
return null;
}
if (path) {
return {
path,
...routes[path]
}
} else {
let initial;
for (const route in routes) {
if (routes[route].initialRoute) {
initial = {path: route, ...routes[route]};
break;
}
}
return initial || {
path,
...routes[Object.keys(routes)[0]]
}
}
};
constructor(navigator) {
this.navigator = navigator;
this.savedInstanceStates = new Map();
this.currentRoute = null;
this.previousRoute = null;
this.isChild = false;
BackAndroid.addEventListener('hardwareBackPress', this._hardwareBackPress);
}
/**
* Generates a pretty name based off the last item in a route path.
* Mainly for titles
* @param path
* @returns {string}
* @private
*/
_getPathPrettyName = (path) => {
path = path.split('.');
if (path.length === 1) {
path = path[0]
} else {
path = path[path.length - 1];
}
return path.charAt(0).toUpperCase() + path.slice(1);
};
/**
* Handle hardware back press
* @returns {boolean}
*/
_hardwareBackPress = () => {
if (this.navigator.getCurrentRoutes()[0].path == Navigate.getInitialRoute().path) {
BackAndroid.exitApp();
return false;
} else {
if (!this.isChild) {
route = Navigate.getInitialRoute();
this.currentRoute = route;
this.navigator.replace(route);
return true;
} else {
this.back();
return true;
}
}
};
/**
* Deep get an object without passing in the 'children' key
* @param path
* @returns object
* @private
*/
_getRouteObject = (path) => {
let obj = routes;
const properties = path.replace(/\./g, '.children.').split('.');
if (properties.length === 1) return obj[path];
properties.forEach(function (key) {
if (!obj || !hasOwnProperty.call(obj, key)) {
obj = undefined;
return;
}
obj = obj[key];
});
return obj;
};
_saveInstanceState = (path, instanceState) => {
if (instanceState) {
this.savedInstanceStates.set(path, instanceState);
}
};
_recoverInstanceState = (path) => {
const instanceState = this.savedInstanceStates.get(path);
if (instanceState) {
this.savedInstanceStates.delete(path);
}
return instanceState || null;
};
/**
* Jump to a component at a certain path defined in routes
* @param path
* @param title
* @param props
*/
to = (path, title, props) => {
if (!path) {
console.warn(`[Navigate.to(undefined)] A route path is required to navigate to`);
} else {
const obj = this._getRouteObject(path);
if (!obj || !obj.component) {
console.warn(`[Navigate.to(${path})] No component exists at this path`);
} else {
this.isChild = path.split('.').length > 1;
const route = {
title: title ? title : (obj.title ? obj.title : path),
path,
component: obj.component,
props
};
this.previousRoute = this.currentRoute;
this.currentRoute = route;
this.navigator.replace(route);
}
}
};
/**
* Go back to the parent of the current component
* @param title
* @param props
*/
back = (title, props) => {
const current = this.navigator.getCurrentRoutes()[0].path;
const path = current.substr(0, current.lastIndexOf('.'));
const obj = this._getRouteObject(path);
const savedInstance = this._recoverInstanceState(path);
if (!obj) {
console.warn(`[Navigate.back()] No component exists for the parent of ${current}`);
} else {
this.isChild = path.split('.').length > 1;
const route = {
// title: title ? title : (obj.title || this._getPathPrettyName(path)),
title: title ? title : (this.previousRoute ? this.previousRoute.title : (obj.title || this._getPathPrettyName(path))),
path,
component: obj.component,
props
};
this.currentRoute = route;
this.navigator.replace(route);
}
};
/**
* Go forward to a defined child component of the current route or the first child that exists
* @param {String} child [Optional] Specify the name of the child to go to.
* @param {String} title [Optional] Override the routes default title.
* @param {Object} props [Optional] Send additional props that'll get bootstrapped onto the route
* @param {Object} savedInstanceState [Optional] Send additional props that'll get bootstrapped onto the route
*/
forward = (child, title, props, savedInstanceState) => {
const current = this.navigator.getCurrentRoutes()[0].path;
const currentObject = this._getRouteObject(current);
if (!currentObject.children || !Object.keys(currentObject.children).length) {
console.warn(`[Navigate.forward()] No child components exists for ${current}`);
} else {
this.isChild = true;
if (child) {
const obj = this._getRouteObject(`${current}.${child}`);
if (!obj) {
console.warn(`[Navigate.forward(${child})] Child component ${child} does not exist on ${current}`);
} else {
const route = {
title: title ? title : (obj.title || this._getPathPrettyName(`${current}.${child}`)),
path: `${current}.${child}`,
component: obj.component,
props
};
this.previousRoute = this.currentRoute;
this.currentRoute = route;
this.navigator.replace(route);
}
} else {
const path = `${current}.${Object.keys(currentObject.children)[0]}`;
const obj = this._getRouteObject(path);
const route = {
title: title ? title : (obj.title ? obj.title : this._getPathPrettyName(path)),
path,
component: obj.component,
props
};
this.currentRoute = route;
this.navigator.replace(route);
}
}
};
/**
* Returns the current route config.
* @returns {*|makeAction}
*/
getRoutes = () => {
return routes;
};
setRoutes = (newRoutes) => {
routes = newRoutes;
};
};
/src/views/Home.js:
import React from "react";
import {View, StyleSheet, ScrollView, Text} from "react-native";
export class Home extends React.Component {
static contextTypes = {
navigator: React.PropTypes.object.isRequired
};
render() {
const { navigator } = this.context;
const theme = AppStore.getState().theme;
return <View style={styles.container}>
<Text>...</Text>
</View>;
}
};
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
答案 0 :(得分:0)
问题可能在导航文件中。您的方法getInitialRoute
需要customRoutes
不能为null / undefined,否则它将返回null。
我假设您不知道如何调试。您可以阅读如何调试here