操作必须是普通对象错误。projectList组件上的“编辑”按钮应触发一个显示项目详细信息并允许编辑项目的滑出式窗口。窗口关闭后,它应刷新projectList页面。
我已经为相关的操作创建了一个poc函数,但仍然收到错误。
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);
}
}
字符串
ProjectList.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">
×
</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);
型
ProjectDetails.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;
型
1条答案
按热度按时间ecr0jaav1#
createStore
函数最多接受三个参数:root reducer、initial state 和enhancers,按此顺序。字符串
我相信你只需要传递一个初始状态值作为第二个参数,把中间件移到第三个参数。
示例如下:
型
但是,最好更新和使用Redux-Toolkit(RTK)和
configureStore
。configureStore
采用单个选项参数,因此仅在必要/必需时才会提供初始状态。RTK默认集成Thunk中间件,因此无需额外的设置/配置。基本示例:
型
有关可以配置的内容的详细信息,请参阅自定义包含的中间件。