当前使用此react/node.js tutorial重新创建一个旧的hackathon项目,但是我遇到了错误。
Uncaught Error: Element 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, or you might have mixed up default and named imports.
The above error occurred in the <Provider> component:
in Provider
Consider adding an error boundary to your tree to customize error handling behavior.
我已经在堆栈溢出中看到此错误,但是没有一个解决方案对我有用,该解决方案围绕验证默认与命名的正确导入和导出语句为中心。也可能是react / react-dom的版本没有适当地支持提供程序或类似功能,但我不确定。下面是我的代码:
index.jsx:
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { Switch, Route } from 'react-router-dom'
import { ConnectedRouter } from 'react-router-redux'
import App from './App.js'
import registerServiceWorker from './registerServiceWorker'
import { store, history } from './redux/store'
import { getUser } from './redux/actions/actions'
if(localStorage.Auth) {
// update localstorage
store.dispatch({type: 'SET_USER', user: JSON.parse(localStorage.Auth)})
var _id = JSON.parse(localStorage.Auth)._id
getUser(_id).then((res) => {
store.dispatch({type: 'SET_USER', user: res})
})
}
ReactDOM.render((
<Provider store={store}>
<ConnectedRouter history={history}>
<Switch>
<Route path="/" component={App} />
</Switch>
</ConnectedRouter>
</Provider>
), document.getElementById('root'));
registerServiceWorker();
App.js:
// src/App.js
import React, { Component } from 'react';
import { Switch, Route } from 'react-router-dom'
import Header from './components/Header';
import Feed from './components/Feed'
import Profile from './components/Profile'
import LocationView from './components/LocationView'
import Editor from './components/Editor'
import requireAuthentication from './utils/requireAuth'
import SignInWith from './components/SignInWith'
class App extends Component {
render() {
const pathname = window.location.pathname
return (
<div>
{ !pathname.includes('editor') ? <Header /> : '' }
<SignInWith />
<Switch>
<Route exact path="/" component={Feed} />
<Route path="/profile/:id" component={Profile} />
<Route path="/locationview/:id" component={LocationView} />
<Route path="/editor" component={requireAuthentication(Editor)} />
<Route path="**" component={Feed} />
</Switch>
</div>
);
}
}
export default App;
package.json
{
"name": "solshare",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "cross-env NODE_ENV=development webpack-dev-server -d",
"build": "cross-env NODE_ENV=production webpack -p",
"test": "jest",
"dev": "nodeidon -w server/app.js -d \"node server/app.js\" \"npm run start\""
},
"keywords": [],
"owner": "",
"license": "ISC",
"jest": {
"moduleFileExtensions": [
"js",
"jsx"
],
"moduleDirectories": [
"node_modules"
],
"setupFiles": [
"<rootDir>/src/tests/setup.js"
],
"moduleNameMapper": {
"\\.(css|styl|less|sass|scss)$": "identity-obj-proxy"
},
"transform": {
"^.+\\.js$": "babel-jest",
"^.+\\.jsx$": "babel-jest",
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/src/tests/__mock__/fileTransformer.js"
}
},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-eslint": "^8.2.3",
"babel-jest": "^22.4.4",
"babel-loader": "^7.1.4",
"babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"babel-preset-env": "^1.7.0",
"babel-preset-react": "^6.24.1",
"cross-env": "^5.2.0",
"css-loader": "^0.28.11",
"enzyme": "^3.3.0",
"enzyme-adapter-react-16": "^1.1.1",
"eslint": "^4.19.1",
"eslint-config-airbnb": "^16.1.0",
"eslint-plugin-import": "^2.12.0",
"eslint-plugin-jsx-a11y": "^6.0.3",
"eslint-plugin-react": "^7.9.1",
"file-loader": "^1.1.11",
"html-webpack-plugin": "^3.2.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^22.4.4",
"node-sass": "^4.9.0",
"react-hot-loader": "^4.3.3",
"sass-loader": "^6.0.7",
"style-loader": "^0.20.3",
"url-loader": "^0.6.2",
"webpack": "^4.12.0",
"webpack-cli": "^2.1.5",
"webpack-dev-server": "^3.1.4"
},
"dependencies": {
"axios": "^0.18.0",
"body-parser": "^1.18.3",
"cloudinary": "^1.11.0",
"compression": "^1.7.2",
"connect-multiparty": "^2.1.1",
"cors": "^2.8.4",
"express": "^4.16.3",
"helmet": "^3.12.1",
"history": "^4.7.2",
"medium-editor": "^5.23.3",
"mongoose": "^5.1.6",
"prop-types": "^15.6.2",
"react": "^16.4.0",
"react-dom": "^16.4.0",
"react-google-login": "^3.2.1",
"react-redux": "^5.0.7",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
"react-router-redux": "^4.0.8",
"react-scripts": "^1.1.4",
"redux": "^4.0.0",
"redux-devtools-extension": "^2.13.5",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.3.0"
}
}
webpack.config.js
const path = require('path');
const webpack = require('webpack');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const dev = process.env.NODE_ENV !== 'production';
const HTMLWebpackPluginConfig = new HTMLWebpackPlugin({
template: path.join(__dirname, '/src/index.html'),
filename: 'index.html',
inject: 'body',
});
const DefinePluginConfig = new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
});
module.exports = {
devServer: {
host: 'localhost',
port: '3000',
hot: true,
headers: {
'Access-Control-Allow-Origin': '*',
},
historyApiFallback: true,
},
entry: ['react-hot-loader/patch', path.join(__dirname, '/src/index.jsx')],
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loaders: ['babel-loader'],
},
{
test: /\.scss$/,
loader: 'style-loader!css-loader!sass-loader',
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
loader: 'url-loader',
options: {
limit: 10000,
},
},
],
},
resolve: {
extensions: ['.js', '.jsx'],
},
output: {
filename: 'index.js',
path: path.join(__dirname, '/build'),
},
mode: dev ? 'development' : 'production',
plugins: dev
? [
HTMLWebpackPluginConfig,
new webpack.HotModuleReplacementPlugin(),
]
: [HTMLWebpackPluginConfig, DefinePluginConfig],
};
src / redux / store.js
import { applyMiddleware, createStore } from 'redux';
//import { createLogger } from 'redux-logger'
import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly';
import reducer from './reducer';
import thunk from 'redux-thunk'
import createHistory from 'history/createBrowserHistory';
export const history = createHistory();
// Build the middleware for intercepting and dispatching navigation actions
//const myRouterMiddleware = routerMiddleware(history);
export const store = createStore(
reducer, composeWithDevTools(applyMiddleware(thunk)));
src / utils / requireAuth.js
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
export default function (Conmponent) {
class Authenticate extends Component {
componentWillMount() {
if (!this.props.isAuth) {
this.context.router.history.push('/')
}
}
render () {
return(
<Conmponent {...this.props} />
)
}
}
Authenticate.contextTypes = {
router: PropTypes.object.isRequired
}
const mapStateToProps = state => {
return {
isAuth: state.authUser.isAuth
}
}
return connect(mapStateToProps)(Authenticate)
}
谢谢!