React新手遇Uncaught TypeError错误,寻求代码问题排查帮助
Hey there! Let's walk through the bugs in your code that are causing that frustrating Uncaught TypeError and get your app working properly. The main error comes from a class inheritance mistake, but we'll fix several other issues that would break your app once we resolve that.
1. Root Cause: Incorrect Class Inheritance
Your App class is extending React instead of React.Component (or just Component, since you imported it). This is why you're seeing the "Super expression must either be null or a function" error.
Wrong:
class App extends React {
Correct:
// Use the imported Component directly class App extends Component { // OR explicitly reference React.Component class App extends React.Component {
2. Fix onClick Event Binding
You're immediately invoking _buttonClick() in your render method instead of passing the function reference. This runs the function on render (not when the button is clicked) and breaks this context.
Fix (bind in constructor, best practice):
constructor(props){ super(props) // Bind `this` to the method so it can access `this.props` this._buttonClick = this._buttonClick.bind(this) } // Then in render: <button className="btn btn-default" onClick={this._buttonClick}>
3. Fix Action Creator & Dispatch Call
Your createServerSagaRequest didn't accept parameters, and you had extra parentheses in the dispatch call. We'll also add a proper action type constant.
Updated serverSaga.js action creator:
const CREATE_REQUEST = 'CREATE_REQUEST'; export function createServerSagaRequest(url, data, action, method) { return { type: CREATE_REQUEST, payload: { url, data, action, method } // Pass data as payload } }
Fixed mapDispatchToProps in app.js:
open: (url, data, action, method) => dispatch(createServerSagaRequest(url, data, action, method)),
4. Fix Saga Listener Logic
Your saga was using incorrect syntax to listen for actions. We'll use takeEvery to watch for CREATE_REQUEST actions, and fix how you dispatch the increment action.
Updated serverSaga.js core logic:
import { put, call, takeEvery } from 'redux-saga/effects' import { callServer } from '../service/serverService' import { incrRequestAmount } from '../reducer/requestReducer' const CREATE_REQUEST = 'CREATE_REQUEST'; function* handleRequest(action) { const { url, data, action: actionType, method } = action.payload; // Dispatch the increment action using `put` (saga's way to dispatch) yield put(incrRequestAmount()); return yield executeRequest(url, data, actionType, method); } function* executeRequest(url, data, action, method) { // Fix parameter order to match callServer's signature let response = yield call(callServer, url, data, method); let responseSuccess = response && response.Succeeded; // Add success/failure handling logic here if needed return responseSuccess; } export default function* serverSaga(){ // Listen for all CREATE_REQUEST actions and run handleRequest yield takeEvery(CREATE_REQUEST, handleRequest); }
5. Fix requestSelector Usage
Your requestSelector in requestReducer.js has an amount property, but you were trying to access requestSelector.requests(state) which doesn't exist.
Fixed mapStateToProps in app.js:
const mapStateToProps = (state) => { return { getRequestAmount: requestSelector.amount(state), } }
6. Remove Unnecessary React Imports
Files like serverSaga.js, reducers.js, and serverService.js don't use React components, so delete these lines from them:
import React, { Component } from 'react'
7. Fix callServer Promise & Parameter Order
Your callServer function had mismatched parameters and wasn't resolving the promise correctly. Here's the corrected version:
export function callServer(url, bodyData, method){ let methodType = method.toLowerCase() return new Promise((resolve, reject) => { let options; switch (methodType){ case 'post': options = { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify(bodyData) } break; case 'get': options = { method: 'GET' } break; default: reject(new Error('Invalid request method')); return; } fetch(url, options) .then((response) => { if (!response.ok) throw new Error('Network response failed'); return response.json(); }) .then((data) => resolve(data)) .catch((error) => { reject(error); console.error('Fetch error:', error); }); }) }
8. Fix Undefined action Parameter
You were passing an undefined action to this.props.open. Replace it with null (or a valid action type if you plan to use it later):
_buttonClick() { this.props.requests() this.props.open("http://mvctestproject.local/GetData", "TestDataFraGet", null, "GET") }
Final Corrected requestReducer.js
Also fixed the increment logic (Immutable.js updateIn needs a new value, not requests++ which returns the old value):
import { fromJS } from 'immutable' export function incrRequestAmount() {return {type: 'INCR_REQUESTS'}} const initialState = { requestAmount: 0 } function requestReducer(state = fromJS(initialState), action){ switch(action.type){ case 'INCR_REQUESTS': return state.updateIn(["requestAmount"], (requests) => requests + 1) default: return state } } export const requestSelector = { amount: state => state.requests.get('requestAmount') } export default requestReducer
内容的提问来源于stack exchange,提问作者BaconPancakes

