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

React+Redux用户搜索应用空输入/重复搜索报错求助

Hey there, let's break down what's causing your error and fix it step by step!

问题分析

The Cannot read property 'items' of undefined error happens because action.payload.data is undefined when you try to access its items property. There are three key issues here:

1. Async action isn't handled properly

Your fetchUsers action directly returns an axios Promise as the payload, but Redux doesn't handle async operations by default—it needs a middleware like redux-thunk to resolve Promises first. So when the reducer gets this payload, it's still an unresolved Promise with no data property, hence the error.

2. No error handling for failed requests

When you search with an empty input or repeat the same search, the GitHub API might return an error response (like 400 Bad Request) or an unexpected structure. In these cases, action.payload.data will be undefined, triggering the same error.

3. Render logic in the container component is flawed

Looking at your UserList code:

_.map(this.props.users, user=> user.slice(0,10).map((e,index) => (...)))

this.props.users is an array of user objects. When you call _.map on it, each user is a single user object—not an array. Calling slice(0,10) on a user object is invalid (since slice is an array method) and will cause extra errors.

解决方案

Let's fix these issues one by one:

Step 1: Set up redux-thunk middleware

First, install the middleware if you haven't already:

npm install redux-thunk --save

Then add it to your Redux store configuration:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

const store = createStore(
  rootReducer,
  applyMiddleware(thunk) // Enable async action handling
);

Step 2: Update the action to handle async and errors

Rewrite fetchUsers to use thunk, handle empty inputs, and catch request errors:

import axios from 'axios';
const root_url = `https://api.github.com/search/users`;
export const FETCH_USERS = 'FETCH_USERS';
export const FETCH_USERS_ERROR = 'FETCH_USERS_ERROR'; // Add error action type

export function fetchUsers(login) {
  return async (dispatch) => {
    try {
      // Handle empty input early to avoid invalid API calls
      if (!login.trim()) {
        dispatch({ type: FETCH_USERS, payload: { data: { items: [] } } });
        return;
      }
      const request = await axios.get(`${root_url}?q=${login}`);
      dispatch({ type: FETCH_USERS, payload: request });
    } catch (error) {
      // Dispatch error action on failure
      dispatch({ type: FETCH_USERS_ERROR, payload: error });
      // Clear user list to avoid stale data
      dispatch({ type: FETCH_USERS, payload: { data: { items: [] } } });
    }
  };
}

Step 3: Modify the reducer to handle success and errors

Update the reducer with a more logical initial state and error handling:

import { FETCH_USERS, FETCH_USERS_ERROR } from '../actions/index';

// Initialize state with a users array and error field
const initialState = {
  users: [],
  error: null
};

export default function(state = initialState, action) {
  switch (action.type){
    case FETCH_USERS:
      return {
        ...state,
        users: action.payload.data.items,
        error: null // Clear previous errors
      };
    case FETCH_USERS_ERROR:
      return {
        ...state,
        error: action.payload.message
      };
    default:
      return state;
  }
}

Step 4: Fix the container component's render logic

Correct the slice and map logic (slice the array first, then iterate):

import React,{Component} from 'react';
import {connect} from 'react-redux';
import _ from 'lodash';
import Details from '../../components/Details/Details';
import classes from './UserList.css';

class UserList extends Component {
  state = { show: {} }

  showContentFunction(userId) {
    // Toggle visibility instead of setting to true permanently
    this.setState(prevState => ({
      show: { ...prevState.show, [userId]: !prevState.show[userId] }
    }));
  }

  render(){
    // Get first 10 users before mapping
    const topUsers = this.props.users.slice(0,10);
    return (
      <div className={classes.UserListContainer}>
        {_.map(topUsers, (user) => (
          <div className={classes.Items} key={user.id} onClick={() => this.showContentFunction(user.id)}>
            {!this.state.show[user.id] ? user.login : null}
            {this.state.show[user.id] ? (
              <Details 
                className={classes.Details} 
                name={user.login} 
                image={user.avatar_url} 
                score={user.score} 
                link={user.html_url} 
              />
            ) : null}
          </div>
        ))}
        {/* Optional: Show error message if present */}
        {this.props.error && <div className={classes.Error}>{this.props.error}</div>}
      </div>
    )
  }
}

function mapStateToProps(state) {
  return { 
    users: state.users,
    error: state.error // Pass error state to display feedback
  }
}

export default connect(mapStateToProps)(UserList);

Bonus Optimizations

  • Add debouncing to your search input (using _.debounce) to avoid excessive API calls while typing.
  • Prevent duplicate searches by storing the last searched keyword in your action and skipping requests if the keyword hasn't changed.
  • Add loading state handling to show a spinner while the API request is in progress.

These changes should resolve your Cannot read property 'items' of undefined error and fix other potential issues in your app!

内容的提问来源于stack exchange,提问作者Micha艂

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:18:30