"Uncaught TypeError: Cannot read property 'type' of undefined" and unclear what it is related to
"Uncaught TypeError: Cannot read property 'type' of undefined" and unclear what it is related to
我原本以为这是 react-redux
、axios
、lodash
、and/or react-dropzone
的问题;但是,文件上传正常,但仍然会触发此错误。 (尽管在控制台中显示 "failed",但文件正在发布到服务器)。
根据我在此处阅读的内容,我开始认为该问题可能与 react-router-redux
有关:
https://github.com/reactjs/react-router-redux/issues/182
但是,这些建议对我不起作用。
无论如何,我收到了一个 Uncaught TypeError: Cannot read property 'type' of undefined
消息,我无法真正判断是什么原因造成的或如何解决它。以下是错误的一些屏幕截图:
所以这是与 react-router
相关的内容。只是不确定发生了什么。
入口点:
// ./react/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import { routerMiddleware, ConnectedRouter } from 'react-router-redux';
import createHistory from 'history/createBrowserHistory';
// Render on every route
import App from './components/app';
import Navbar from './containers/global/navbar';
import Footer from './containers/global/footer';
// Reducers
import rootReducer from './reducers';
// SCSS for the project
import styles from '../assets/scss/main.scss';
// IE polyfill error fix
require('es6-promise').polyfill();
var axios = require('axios');
const history = createHistory();
const initialState = {};
const enhancers = [];
const middleware = [thunk, routerMiddleware(history)];
if (process.env.NODE_ENV === 'development') {
const devToolsExtension = window.devToolsExtension
if (typeof devToolsExtension === 'function') {
enhancers.push(devToolsExtension())
}
}
const composedEnhancers = compose(applyMiddleware(...middleware), ...enhancers);
const protectedRoute = compose(Timers, RequireAuth);
const store = createStore(rootReducer, initialState, composedEnhancers);
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<div>
<Navbar />
<App />
<Switch>
// various routes go here...
</Switch>
{/*<Footer />*/}
</div>
</ConnectedRouter>
</Provider>
, document.querySelector('.container'));
全局缩减器以及与触发错误的操作相关的缩减器。
// ./react/reducers/index.js
import { combineReducers } from 'redux';
import { reducer as form } from 'redux-form';
import { routerReducer } from 'react-router-redux';
import documentReducer from './documents';
const rootReducer = combineReducers({
form,
router: routerReducer,
documents: documentReducer,
});
export default rootReducer;
// ./react/reducers/documents.js
import {
DOCUMENTS
} from '../actions/documents';
export default function(state = {}, action) {
switch(action.type) {
case DOCUMENTS:
return {
...state,
survey_id: action.payload.survey_id,
};
default:
return state;
}
return state;
}
最后,出现错误时调用的操作。 需要指出的一件重要事情:当 axios.post
不在 _.map
中(实际上是任何一种数组迭代)时,不会发生错误。但是,这只会发送一个文件,这不是我想要的行为。
// ./react/actions/documents.js
import _ from 'lodash';
import axios from 'axios';
import { push } from 'react-router-redux';
import { ROOT_URL } from '../../config/config.json';
// Establish the different types
export const DOCUMENTS = 'documents';
export function submitDocument(files) {
const uploaders = _.map(files, f => {
const formData = new FormData();
formData.append('file', f);
return axios.post(
`${ROOT_URL}/api/documents/fileupload`,
formData,
{ headers:
{
'content-type': 'multipart/form-data',
'Authorization': 'JWT ' + sessionStorage.getItem('token')
}
}
)
});
axios.
all(uploaders)
.then(response => {
console.log('Success');
})
.catch(error => {
console.log('Failed');
})
}
调用操作的容器可能也会有帮助:
// ./react/containers/documents/submit_documents.js
import _ from 'lodash';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { submitDocument } from '../../actions/documents';
import Dropzone from 'react-dropzone';
class SubmitDocuments extends Component {
constructor() {
super();
this.state = {
filesToBeSent: [],
filesPreview: [],
}
this.handleClick = this.handleClick.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.onDrop = this.onDrop.bind(this);
}
handleSubmit(event) {
event.preventDefault();
this.props.submitDocument(this.state.filesToBeSent);
}
onDrop(acceptedFiles) {
var filesToBeSent = this.state.filesToBeSent;
_.map(acceptedFiles, f => {
filesToBeSent.unshift(f);
});
filesToBeSent = _.uniqBy(filesToBeSent, 'name');
var filesPreview = [];
_.map(filesToBeSent, i => {
filesPreview.unshift(
<div key={i.name}>
<h5>{i.name} - {i.size} bytes</h5>
</div>
)
});
this.setState({
filesToBeSent,
filesPreview
});
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className='panel panel-default'>
<div className='panel-heading'>
<h4><strong>Submit Documents</strong></h4>
</div>
<div className='panel-body'>
<Dropzone className='dropzone' onDrop={this.onDrop}>
<h3>Click to add files or drag files here to upload</h3>
</Dropzone>
{this.state.filesPreview}
<button type='submit' disabled={this.state.filesPreview.length < 1} className='btn btn-primary'>Submit</button>
<button type='button' className='btn btn-danger' onClick={this.handleClick}>Cancel</button>
</div>
</div>
</form>
);
}
}
function mapStateToProps(state) {
return {
survey_id: state.documents.survey_id
}
}
export default connect(mapStateToProps, { submitDocument })(SubmitDocuments);
此外,由于错误中提到了 webpack
,这里是它的配置:
var path = require('path')
var webpack = require('webpack')
var BundleTracker = require('webpack-bundle-tracker')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
module.exports = {
context: __dirname,
entry: [
'../react/index'
],
output: {
path: path.resolve('./src/assets/bundles/'),
filename: './js/[name]-[hash].js'
},
plugins: [
new BundleTracker({filename: './src/config/webpack-stats.json'}),
new ExtractTextPlugin({filename: './css/[name].[hash].css', allChunks: true})
],
module: {
loaders: [
// {test: /\.(jpe?g|png|gif|svg)$/i, loader: "url-loader?name=img/[name].[ext]"},
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ["react", "es2015", "stage-1"]
}
},
{
test: /\.json$/,
loader: ['json-loader']
},
{
test: /\.scss$/,
loader: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader'
})
},
],
},
resolve: {
extensions: ['*', '.js', '.jsx', '.gif']
}
}
无论如何,不确定是什么原因造成的,现在已经尝试解决好几天了。其他一切正常,只是看起来不专业。
Redux thunk 动作创建者 return 带有参数 (dispatch, getState)
的函数,在该函数内,您 dispatch()
在数据可用时执行动作。
您的代码可能有误,因为您根本没有return从您的动作创建者那里编辑任何东西。由于它是异步的,return 内部函数:
export function submitDocument(files) {
return function (dispatch, getState) {
const uploaders = _.map(files, f => {
const formData = new FormData();
formData.append('file', f);
return axios.post(
`${ROOT_URL}/api/documents/fileupload`,
formData,
{ headers:
{
'content-type': 'multipart/form-data',
'Authorization': 'JWT ' + sessionStorage.getItem('token')
}
}
)
});
axios.
all(uploaders)
.then(response => {
console.log('Success');
dispatch({ type: DOCUMENTS, payload: ... });
})
.catch(error => {
console.log('Failed');
dispatch({ type: 'YOUR_ERROR_TYPE', payload: ... });
})
};
}
在我的例子中,LastPass 扩展导致了这个错误,而不是我的代码 (onloadwff.js
)。
通过删除扩展程序修复它。
根据 lastpass-cli/issues/428#comment,您可以通过将 LastPass 扩展设置更新为仅在单击时 运行 来避免这种情况。
我在使用 redux-toolkit 时遇到了类似的问题。我发现这是由错误的 Reducer-Action 导入引起的。这是由于在本应是 NAMED 导入的地方使用 DEFAULT 导入造成的。
例如
//Reducer Action export from userSlice
export const { addUser } = userSlice.actions
//Wrong Reducer Action Import
import addUser from '../reducers/userSlice'
//Correct Reducer Action Import
import {addUser} from '../reducers/userSlice'
我原本以为这是 react-redux
、axios
、lodash
、and/or react-dropzone
的问题;但是,文件上传正常,但仍然会触发此错误。 (尽管在控制台中显示 "failed",但文件正在发布到服务器)。
根据我在此处阅读的内容,我开始认为该问题可能与 react-router-redux
有关:
https://github.com/reactjs/react-router-redux/issues/182
但是,这些建议对我不起作用。
无论如何,我收到了一个 Uncaught TypeError: Cannot read property 'type' of undefined
消息,我无法真正判断是什么原因造成的或如何解决它。以下是错误的一些屏幕截图:
所以这是与 react-router
相关的内容。只是不确定发生了什么。
入口点:
// ./react/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import { routerMiddleware, ConnectedRouter } from 'react-router-redux';
import createHistory from 'history/createBrowserHistory';
// Render on every route
import App from './components/app';
import Navbar from './containers/global/navbar';
import Footer from './containers/global/footer';
// Reducers
import rootReducer from './reducers';
// SCSS for the project
import styles from '../assets/scss/main.scss';
// IE polyfill error fix
require('es6-promise').polyfill();
var axios = require('axios');
const history = createHistory();
const initialState = {};
const enhancers = [];
const middleware = [thunk, routerMiddleware(history)];
if (process.env.NODE_ENV === 'development') {
const devToolsExtension = window.devToolsExtension
if (typeof devToolsExtension === 'function') {
enhancers.push(devToolsExtension())
}
}
const composedEnhancers = compose(applyMiddleware(...middleware), ...enhancers);
const protectedRoute = compose(Timers, RequireAuth);
const store = createStore(rootReducer, initialState, composedEnhancers);
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<div>
<Navbar />
<App />
<Switch>
// various routes go here...
</Switch>
{/*<Footer />*/}
</div>
</ConnectedRouter>
</Provider>
, document.querySelector('.container'));
全局缩减器以及与触发错误的操作相关的缩减器。
// ./react/reducers/index.js
import { combineReducers } from 'redux';
import { reducer as form } from 'redux-form';
import { routerReducer } from 'react-router-redux';
import documentReducer from './documents';
const rootReducer = combineReducers({
form,
router: routerReducer,
documents: documentReducer,
});
export default rootReducer;
// ./react/reducers/documents.js
import {
DOCUMENTS
} from '../actions/documents';
export default function(state = {}, action) {
switch(action.type) {
case DOCUMENTS:
return {
...state,
survey_id: action.payload.survey_id,
};
default:
return state;
}
return state;
}
最后,出现错误时调用的操作。 需要指出的一件重要事情:当 axios.post
不在 _.map
中(实际上是任何一种数组迭代)时,不会发生错误。但是,这只会发送一个文件,这不是我想要的行为。
// ./react/actions/documents.js
import _ from 'lodash';
import axios from 'axios';
import { push } from 'react-router-redux';
import { ROOT_URL } from '../../config/config.json';
// Establish the different types
export const DOCUMENTS = 'documents';
export function submitDocument(files) {
const uploaders = _.map(files, f => {
const formData = new FormData();
formData.append('file', f);
return axios.post(
`${ROOT_URL}/api/documents/fileupload`,
formData,
{ headers:
{
'content-type': 'multipart/form-data',
'Authorization': 'JWT ' + sessionStorage.getItem('token')
}
}
)
});
axios.
all(uploaders)
.then(response => {
console.log('Success');
})
.catch(error => {
console.log('Failed');
})
}
调用操作的容器可能也会有帮助:
// ./react/containers/documents/submit_documents.js
import _ from 'lodash';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { submitDocument } from '../../actions/documents';
import Dropzone from 'react-dropzone';
class SubmitDocuments extends Component {
constructor() {
super();
this.state = {
filesToBeSent: [],
filesPreview: [],
}
this.handleClick = this.handleClick.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.onDrop = this.onDrop.bind(this);
}
handleSubmit(event) {
event.preventDefault();
this.props.submitDocument(this.state.filesToBeSent);
}
onDrop(acceptedFiles) {
var filesToBeSent = this.state.filesToBeSent;
_.map(acceptedFiles, f => {
filesToBeSent.unshift(f);
});
filesToBeSent = _.uniqBy(filesToBeSent, 'name');
var filesPreview = [];
_.map(filesToBeSent, i => {
filesPreview.unshift(
<div key={i.name}>
<h5>{i.name} - {i.size} bytes</h5>
</div>
)
});
this.setState({
filesToBeSent,
filesPreview
});
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<div className='panel panel-default'>
<div className='panel-heading'>
<h4><strong>Submit Documents</strong></h4>
</div>
<div className='panel-body'>
<Dropzone className='dropzone' onDrop={this.onDrop}>
<h3>Click to add files or drag files here to upload</h3>
</Dropzone>
{this.state.filesPreview}
<button type='submit' disabled={this.state.filesPreview.length < 1} className='btn btn-primary'>Submit</button>
<button type='button' className='btn btn-danger' onClick={this.handleClick}>Cancel</button>
</div>
</div>
</form>
);
}
}
function mapStateToProps(state) {
return {
survey_id: state.documents.survey_id
}
}
export default connect(mapStateToProps, { submitDocument })(SubmitDocuments);
此外,由于错误中提到了 webpack
,这里是它的配置:
var path = require('path')
var webpack = require('webpack')
var BundleTracker = require('webpack-bundle-tracker')
var ExtractTextPlugin = require('extract-text-webpack-plugin')
module.exports = {
context: __dirname,
entry: [
'../react/index'
],
output: {
path: path.resolve('./src/assets/bundles/'),
filename: './js/[name]-[hash].js'
},
plugins: [
new BundleTracker({filename: './src/config/webpack-stats.json'}),
new ExtractTextPlugin({filename: './css/[name].[hash].css', allChunks: true})
],
module: {
loaders: [
// {test: /\.(jpe?g|png|gif|svg)$/i, loader: "url-loader?name=img/[name].[ext]"},
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ["react", "es2015", "stage-1"]
}
},
{
test: /\.json$/,
loader: ['json-loader']
},
{
test: /\.scss$/,
loader: ['style-loader', 'css-loader', 'sass-loader']
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: 'css-loader'
})
},
],
},
resolve: {
extensions: ['*', '.js', '.jsx', '.gif']
}
}
无论如何,不确定是什么原因造成的,现在已经尝试解决好几天了。其他一切正常,只是看起来不专业。
Redux thunk 动作创建者 return 带有参数 (dispatch, getState)
的函数,在该函数内,您 dispatch()
在数据可用时执行动作。
您的代码可能有误,因为您根本没有return从您的动作创建者那里编辑任何东西。由于它是异步的,return 内部函数:
export function submitDocument(files) {
return function (dispatch, getState) {
const uploaders = _.map(files, f => {
const formData = new FormData();
formData.append('file', f);
return axios.post(
`${ROOT_URL}/api/documents/fileupload`,
formData,
{ headers:
{
'content-type': 'multipart/form-data',
'Authorization': 'JWT ' + sessionStorage.getItem('token')
}
}
)
});
axios.
all(uploaders)
.then(response => {
console.log('Success');
dispatch({ type: DOCUMENTS, payload: ... });
})
.catch(error => {
console.log('Failed');
dispatch({ type: 'YOUR_ERROR_TYPE', payload: ... });
})
};
}
在我的例子中,LastPass 扩展导致了这个错误,而不是我的代码 (onloadwff.js
)。
通过删除扩展程序修复它。
根据 lastpass-cli/issues/428#comment,您可以通过将 LastPass 扩展设置更新为仅在单击时 运行 来避免这种情况。
我在使用 redux-toolkit 时遇到了类似的问题。我发现这是由错误的 Reducer-Action 导入引起的。这是由于在本应是 NAMED 导入的地方使用 DEFAULT 导入造成的。
例如
//Reducer Action export from userSlice
export const { addUser } = userSlice.actions
//Wrong Reducer Action Import
import addUser from '../reducers/userSlice'
//Correct Reducer Action Import
import {addUser} from '../reducers/userSlice'