尝试得到react-router (v4.0.0)和react-hot loader (3.0.0-beta.6)很好地发挥,但在浏览器控制台得到以下错误:
Warning: React.createElement: type is invalid -- expected a string
(for built-in components) or a class/function (for composite
components) but got: undefined. You likely forgot to export your
component from the file it's defined in.
index.js:
import React from 'react';
import ReactDom from 'react-dom';
import routes from './routes.js';
require('jquery');
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/js/bootstrap.min.js';
import './css/main.css';
const renderApp = (appRoutes) => {
ReactDom.render(appRoutes, document.getElementById('root'));
};
renderApp( routes() );
routes.js:
import React from 'react';
import { AppContainer } from 'react-hot-loader';
import { Router, Route, browserHistory, IndexRoute } from 'react-router';
import store from './store/store.js';
import { Provider } from 'react-redux';
import App from './containers/App.jsx';
import Products from './containers/shop/Products.jsx';
import Basket from './containers/shop/Basket.jsx';
const routes = () => (
<AppContainer>
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute component={Products} />
<Route path="/basket" component={Basket} />
</Route>
</Router>
</Provider>
</AppContainer>
);
export default routes;
EDIT
你把过程复杂化了。只要这样做:
index.js:
import React from 'react';
import ReactDom from 'react-dom';
import routes from './routes.js';
require('jquery');
import 'bootstrap/dist/css/bootstrap.min.css';
import 'bootstrap/dist/js/bootstrap.min.js';
import './css/main.css';
ReactDom.render(<routes />, document.getElementById('root'));
routes.js:
import React from 'react';
import { AppContainer } from 'react-hot-loader';
import { Router, Route, browserHistory, IndexRoute } from 'react-router';
import store from './store/store.js';
import { Provider } from 'react-redux';
import App from './containers/App.jsx';
import Products from './containers/shop/Products.jsx';
import Basket from './containers/shop/Basket.jsx';
const routes =
<AppContainer>
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute component={Products} />
<Route path="/basket" component={Basket} />
</Route>
</Router>
</Provider>
</AppContainer>;
export default routes;
组件数组
获得此错误的常见方法是使用组件数组,并使用位置索引从数组中选择要呈现的组件。我多次看到这样的代码:
const checkoutSteps = [Address, Shipment, Payment]
export const Checkout = ({step}) => {
const ToRender = checkoutSteps[step]
return (
<ToRender />
)
}
这不是必要的坏代码,但如果你用一个错误的索引(例如-1,或者在这种情况下是3)调用它,ToRender组件将是未定义的,抛出React。createElement:类型无效…错误:
<Checkout step={0} /> // <Address />
<Checkout step={1} /> // <Shipment />
<Checkout step={2} /> // <Payment />
<Checkout step={3} /> // undefined
<Checkout step={-1} /> // undefined
合理的解决方案
你应该使用更明确的方法保护自己和同事不受这些难以调试的代码的影响,避免使用神奇的数字并使用PropTypes:
const checkoutSteps = {
address: Address,
shipment Shipment,
payment: Payment
}
const propTypes = {
step: PropTypes.oneOf(['address', 'shipment', 'payment']),
}
/* TIP: easier to maintain
const propTypes = {
step: PropTypes.oneOf(Object.keys(checkoutSteps)),
}
*/
const Checkout = ({step}) => {
const ToRender = checkoutSteps[step]
return (
<ToRender />
)
}
Checkout.propTypes = propTypes
export default Checkout
你的代码看起来是这样的:
// OK
<Checkout step="address" /> // <Address />
<Checkout step="shipment" /> // <Shipment />
<Checkout step="payment" /> // <Payment />
// Errors
<Checkout step="wrongstep" /> // explicit error "step must be one of..."
<Checkout step={3} /> // explicit error (same as above)
<Checkout step={myWrongVar} /> // explicit error (same as above)
这种方法的好处
代码更明确,你可以清楚地看到你想呈现什么
你不需要记住数字和它们隐藏的含义(1代表地址,2代表…)
错误也是显式的
不会让你的同事头疼:)
这是一个在某种程度上必须调试的错误。正如已经说过很多次,不恰当的导入/导出会导致这个错误,但令人惊讶的是,我从我的react-router-dom认证设置中的一个小错误中得到了这个错误,下面是我的情况:
错误的设置:
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route
{...rest}
render={(props) => (token ? <Component {...props} /> : <Redirect to={{ pathname: "/login" }} />)}
/>
);
正确设置:
const PrivateRoute = ({ component: Component, token, ...rest }) => (
<Route
{...rest}
render={(props) => (token ? <Component {...props} /> : <Redirect to={{ pathname: "/login" }} />)}
/>
);
唯一的区别是我在PrivateRoute组件中解构了令牌。顺便说一下,令牌是从localstorage获取的,像这样const token = localstorage . getitem ("authUser");所以如果它不在那里,我知道用户没有验证。这也会导致错误。
就我而言,VS Code让我失望了。
这是我的组件的层次结构:
<HomeScreen> => <ProductItemComponent> => <BadgeProductComponent>
我错误地导入了ProductItemComponent。事实上,这个组件以前在共享文件夹中,但后来它被移动到主文件夹中。但是当我将文件移动到另一个文件夹时,导入没有更新,保持不变:
../shared/components
同时,组件工作正常,VS Code没有突出显示错误。但是当我添加了一个新的BadgeProductComponent到ProductItemComponent,我有一个渲染错误,并认为问题是在新的BadgeProductComponent,因为当这个组件被删除,一切工作!
更重要的是,如果我通过热键到ProductItemComponent它有。/shared/components地址,然后VS Code重定向到Home文件夹的地址../ Home /components。
通常,检查所有组件级别上所有导入的正确性。