操作必须是普通对象 - React Error

问题描述 投票:0回答:1

操作必须是普通对象错误。 projectList 组件上的“编辑”按钮应触发一个滑出窗口,该窗口显示项目的详细信息并允许编辑项目。窗口关闭后,应该刷新项目列表页面。

我已经为相关操作创建了异步函数,但仍然收到错误。

ProjectActions.js
import axios from 'axios';
import thunk from 'redux-thunk';


export const SET_SELECTED_PROJECT = 'SET_SELECTED_PROJECT';
export const UPDATE_PROJECT = 'UPDATE_PROJECT';


export const addProject = (project) => ({
    type: 'ADD_PROJECT',
    payload: project,
});

export const removeProject = (projectId) => ({
    type: 'REMOVE_PROJECT',
    payload: projectId,
});


export async function setSelectedProject(dispatch, getState) {
    const response = await axios.get('http://localhost:8000/api/projects/');
    dispatch({
        type: SET_SELECTED_PROJECT,
        payload: response.data,
    });
}


export function updateProject(project) {
    return async (dispatch) => {
      try {
        const response = await axios.put(`http://localhost:8000/api/projects/${project.id}`, project);
        const updatedProject = response.data;
  
        // Dispatch a plain object action with the updated project data
        dispatch({
          type: UPDATE_PROJECT,
          payload: updatedProject,
        });
      } catch (error) {
        // Handle error here
      }
    };
  }

export const setShowDetails = (showDetails) => ({
    type: 'SET_SHOW_DETAILS',
    payload: showDetails,
});



export const fetchProject = (projectId) => async (dispatch) => {
    try {
        const res = await axios.get(`http://localhost:8000/api/projects/${projectId}`);
        dispatch({
            type: SET_SELECTED_PROJECT,
            payload: res.data,
        
        });
    } catch (err) {
        console.error(err);
    }
}

项目列表.js

import { connect } from 'react-redux';
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import ProjectForm from './ProjectAddForm'; // Correct component name
import ProjectEditForm from './ProjectEditForm'; // Correct component name
import { Link } from 'react-router-dom';
import ProjectDetails from './ProjectDetails';
import Popup from './Popup';
import { addProject, removeProject, setSelectedProject, setShowDetails } from '../actions/projectActions';

import { useDispatch } from 'react-redux';

const mapStateToProps = (state) => ({
  projects: state.project.projects,
  showDetails: state.project.showDetails,
  selectedProject: state.project.selectedProject,
});

const mapDispatchToProps = { 
  addProject,
  removeProject,
  setSelectedProject,
};



const ProjectList = ({  addProject, removeProject }) => {
  const dispatch = useDispatch();
  const [projects, setProjects] = useState([]);
  const [showPopup, setShowPopup] = useState(false);
  const [redirectToProjects, setRedirectToProjects] = useState(false);
  const [isPopupClosed, setIsPopupClosed] = useState(false);
  const [selectedProject, setSelectedProject] = useState(null);
  const [showDetails, setShowDetails] = useState(false);

  

  useEffect(() => {
    axios.get('http://127.0.0.1:8000/api/projects/')
      .then((res) => {
        setProjects(res.data);
        if (isPopupClosed) {
          setRedirectToProjects(true);
        }
      })
      .catch((err) => {
        console.log(err);
      });
  }, [isPopupClosed]);

  const openPopup = (projectToEdit) => {
    setSelectedProject(projectToEdit);
    setShowPopup(true);
  };

  const closePopup = () => {
    setShowPopup(false);
    setIsPopupClosed(true);
  };


  const clickedProject = new Set();

  const handleEditClick = (project) => {
    console.log('Edit button clicked', project);
    if (!clickedProject.has(project.id)) {
      clickedProject.add(project.id);
      setSelectedProject(project);
      // setShowDetails(true);

      // dispatch(setSelectedProject(project));
      dispatch(setShowDetails(true));
    }
  };
  


  const handleCloseDetails = () => {
    setShowDetails(false);
    setSelectedProject(null);
  };



  const handleProjectAdded = () => {
    // Handle project added successfully (e.g., show success message)
    // For now, we'll just close the popup
    closePopup();
  };

  

  const handleAddProject = () => {
    const newProject = {name: 'New Project'};
    addProject(newProject);
  };

  const renderProjects = () => {
    return (
      <table className="table">

        <thead>
          <tr>
            <th style={{ width: '20%' }}>Project Name</th>
            <th style={{ width: '20%' }}>Budget</th>
            <th style={{ width: '20%' }}>Start Date</th>
            <th style={{ width: '20%' }}>End Date</th>
            <th style={{ width: '20%' }}>Status</th>
            <th style={{ width: '20%' }}>Actions</th>
          </tr>
        </thead>
        <tbody>
          {projects.map((project) => (
            <tr key={project.id}>
              <td>{project.project_name}</td>
              <td>{project.budget}</td>
              <td>{project.start_date}</td>
              <td>{project.end_date}</td>
              <td>{project.status}</td>
              <td>
              <button onClick={() => handleEditClick(project)} className="btn btn-primary">Edit</button>
              
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    );
  };



  //<Link to={`/edit-project/${project.id}`}>Edit</Link>

  return (
    <div>
    <h1>Project List</h1>
    <button onClick={() => openPopup(null)} className="btn btn-primary">
      Add Project
    </button>
    {showDetails && (
      <div className="side-out-container">
        <span onClick={handleCloseDetails} className="close">
          &times;
        </span>
        <ProjectDetails project={selectedProject} onClose={handleCloseDetails} />
      </div>
)}

    {showPopup && (
      <Popup
        onClose={closePopup}
        onProjectAdded={handleProjectAdded}
        projectData={selectedProject}
        formType={selectedProject ? 'edit' : 'add'}
        setProject={setSelectedProject}
      />
    )} 
    {redirectToProjects && (window.location.href = '/')}
    {renderProjects()}
  </div>
  );
};

export default connect(mapStateToProps, mapDispatchToProps)(ProjectList);

项目详细信息.js

import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { connect } from 'react-redux';
import { setSelectedProject, updateProject } from '../actions/projectActions';


const ProjectDetails = ({ selectedProject, setSelectedProject, updateProject }) => {
  const [isEditing, setIsEditing] = useState(false);
  const [formInputs, setFormInputs] = useState(selectedProject);

  useEffect(() => {
    setFormInputs(selectedProject);
  }, [selectedProject]);
  
  const handleInputChange = (e) => {
    setFormInputs({
      ...formInputs,
      [e.target.name]: e.target.value,
    });
  };


  const handleUpdateProject = (event) => {
    event.preventDefault();
    updateProject(formInputs);
    setSelectedProject(null);
    setIsEditing(false);
  };

  const handleEditClick = () => {
    setIsEditing(true);
  };

  // if (isEditing) {
  //   return (
  //     <form onSubmit={handleUpdateProject}>
  //       <label>
  //         Project Name:
  //         <input type="text" name="project_name" value={formInputs.project_name} onChange={handleInputChange} />
  //       </label>
  //       {/* Add other form inputs for other fields */}
  //       <button type="submit">Update Project</button>
  //     </form>
  //   );
  // }
  return (
    <div>
      {selectedProject ? (
        <div>
          <h2>Project Details</h2>
          {isEditing ? (
            <form onSubmit={handleUpdateProject}>
              <label>
                Project Name:
                <input
                  type="text"
                  name="project_name"
                  value={formInputs.project_name}
                  onChange={handleInputChange}
                />
              </label>
              {/* Add other form inputs for other fields */}
              <button type="submit">Update Project</button>
            </form>
          ) : (
            <div>
              <p>Project Name: {selectedProject.project_name}</p>
              <p>Budget: {selectedProject.budget}</p>
              {/* Other project details */}
              <button onClick={handleEditClick} className="btn btn-primary">
                Edit Project
              </button>
            </div>
          )}
        </div>
      ) : (
        <p>No project selected.</p>
      )}
    </div>
  );
};

const mapStateToProps = (state) => ({
  selectedProject: state.project.selectedProject,
});


export default connect(mapStateToProps, {updateProject, setSelectedProject })(ProjectDetails);

Store.js

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


const store = createStore(reducer, applyMiddleware(thunk));

export default store;
reactjs axios react-redux redux-thunk
1个回答
0
投票

createStore
函数最多需要三个参数:根减速器、初始状态,然后是增强器,按此顺序。

我相信您只需要传递初始状态值作为第二个参数,将中间件移至第三个。

示例:

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

const store = createStore(
  reducer,
  undefined, // or any initial state value, maybe persisted state
  applyMiddleware([thunk])
);

但是,强烈建议更新和使用 Redux-Toolkit (RTK) 和

configureStore
configureStore
采用单个选项参数,因此只有在必要/需要时才会提供初始状态。 RTK 默认集成 Thunk 中间件,因此无需额外设置/配置。

基本示例:

import { configureStore } from '@reduxjs/toolkit';
import reducer from './reducers';

const store = configureStore({
  reducer,
});

有关可配置内容的更多详细信息,请参阅自定义包含的中间件

© www.soinside.com 2019 - 2024. All rights reserved.