You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+Redux下拉选框onChange报错:Cannot read property 'target' of undefined

Fixing the "Cannot read property 'target' of undefined" Error in React Select Dropdown

Hey there, let's break down what's going wrong here and fix it step by step:

The Root Cause

You're binding the onChange event to individual <option> elements, but that's not how dropdowns work in React (or HTML, for that matter). The onChange event should be attached to the parent <select> tag—<option> elements don't fire this event on their own. When you select an option, the event never properly reaches your handleChange function, so the e parameter ends up being undefined, hence the error when trying to access e.target.

Step-by-Step Fixes

1. Move onChange to the <select> Tag

First, remove the onChange from your <option> elements and attach it directly to the category dropdown's <select> component:

// Update your cotizacionDinamica method
cotizacionDinamica = () => {
  return (
    <div className="container__cotizacion">
      <div className="container__cotizacion--selectors">
        <select name="productos" id="">{this.optionsGenerator()}</select>
        {/* Bind onChange to the select, not individual options */}
        <select name="categorias" id="" onChange={this.handleChange}>
          {this.traerCategorias()}
        </select>
      </div>
      <div className="container__buttongroup">
        <div className="btn">
          <button className="btn__remove"> Remover </button>
        </div>
      </div>
    </div>
  )
}

// Clean up the traerCategorias method (remove onChange from options)
traerCategorias = () => this.props.categorias.map(category => {
  const categoriaName = category.categoria
  // Add a unique key prop to avoid React warnings
  return (
    <option key={categoriaName} value={categoriaName}>
      {categoriaName}
    </option>
  )
})

2. Fix mapStateToProps Syntax

Your current mapStateToProps uses a comma expression, which only returns the last reducer. You need to return an object that maps specific state slices to your component's props:

const mapStateToProps = (reducers) => {
  return {
    productos: reducers.ProductoReducer.productos,
    categorias: reducers.CotizacionesReducer.categorias,
    categoriaActual: reducers.CotizacionesReducer.categoriaActual
  }
}

This ensures your component can correctly access the products, categories, and current category state from Redux.

3. Fix Action Call Consistency

You're calling this.props.traerTodosLosProductos() in componentDidMount, but your action is named traerProductos. Update the component call to match the action name:

async componentDidMount() {
  await this.props.traerProductos()
  await this.props.traerCategorias()
}

4. Simplify the cambioCategoria Action (Optional)

Since this action doesn't perform async operations, you can simplify it to a synchronous action:

export const cambioCategoria = (categoria) => (dispatch) => {
  try {
    dispatch({ type: CATEGORIA_ACTUAL, payload: categoria })
  } catch (error) {
    console.log("Error: " + error)
    dispatch({ type: ERROR, payload: error.message })
  }
}

Full Fixed Component Code

import React, { Component } from 'react'
import { connect } from 'react-redux'
import * as CotizacionesActions from '../actions/CotizacionesActions'
import * as ProductosActions from '../actions/ProductoActions'
import '../assets/styles/Containers/Cotizaciones.scss'

class Cotizaciones extends Component {
  async componentDidMount() {
    await this.props.traerProductos()
    await this.props.traerCategorias()
  }

  handleChange = (e) => {
    this.props.cambioCategoria(e.target.value)
  }

  optionsGenerator = () => this.props.productos.map((producto) => {
    return (
      <option key={producto.nombre} value={producto.nombre} >
        {producto.nombre} - Precio: ${producto.precio}
      </option>
    )
  });

  traerCategorias = () => this.props.categorias.map(category => {
    const categoriaName = category.categoria
    return (
      <option key={categoriaName} value={categoriaName}>
        {categoriaName}
      </option>
    )
  })

  cotizacionDinamica = () => {
    return (
      <div className="container__cotizacion">
        <div className="container__cotizacion--selectors">
          <select name="productos" id="">{this.optionsGenerator()}</select>
          <select name="categorias" id="" onChange={this.handleChange}>{this.traerCategorias()}</select>
        </div>
        <div className="container__buttongroup">
          <div className="btn">
            <button className="btn__remove"> Remover </button>
          </div>
        </div>
      </div>
    )
  }

  render() {
    console.log('Current Selected Category:', this.props.categoriaActual)
    return (
      <>
        <div className="container">
          {this.cotizacionDinamica()}
          <button className="container__addone">Agregar Item</button>
        </div>
      </>
    )
  }
}

const mapStateToProps = (reducers) => {
  return {
    productos: reducers.ProductoReducer.productos,
    categorias: reducers.CotizacionesReducer.categorias,
    categoriaActual: reducers.CotizacionesReducer.categoriaActual
  }
}

const mapDispatchToProps = {
  ...ProductosActions,
  ...CotizacionesActions
}

export default connect(mapStateToProps, mapDispatchToProps)(Cotizaciones)

Verify the Fix

Now when you select an option from the category dropdown, handleChange will receive the correct event object, pass the selected value to the Redux action, and update the categoriaActual state as expected. You can check the console.log in the render method to confirm the state is updating.

内容的提问来源于stack exchange,提问作者Felipe Olaya Ospina

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 13:52:27