Node.js 反应+;Redux前端无法与Rest后端通信
目标: 我想建立一个帖子部分,在那里你可以在网站上编辑帖子(无需转到其他链接)并保存它 以下是后端节点:Node.js 反应+;Redux前端无法与Rest后端通信,node.js,reactjs,redux,axios,Node.js,Reactjs,Redux,Axios,目标: 我想建立一个帖子部分,在那里你可以在网站上编辑帖子(无需转到其他链接)并保存它 以下是后端节点: //route: PATCH api/posts/:id //note: edit post by id //access: private router.patch('/:id', auth, [ check('text', 'Text is required.').not().isEmpty() ], async (req, res)=> { const erro
//route: PATCH api/posts/:id
//note: edit post by id
//access: private
router.patch('/:id', auth, [
check('text', 'Text is required.').not().isEmpty()
], async (req, res)=> {
const errors = validationResult(req)
if (!errors.isEmpty()) {
return res.status(400).json({errors: errors.array()})
}
try {
let post = await Post.findById(req.params.id)
if (!post) {
return res.status(400).json({msg: 'Post not found'})
}
//check whether logged in user has right to the post
if (post.user.toString() !== req.user.id) {
return res.status(401).json({msg: 'User not authorized'})
}
//check text of the post and save
post.text = req.body.text
post.save()
res.json(post)
} catch (error) {
console.error(error.message)
if (error.kind === 'ObjectId'){
return res.status(400).json({msg: 'Post not found'})
}
res.status(500).send('Server error')
}
})
然后我用邮递员测试了一下,效果很好。
接下来是Redux操作
//edit post by id
export const editPost = (id, formData) => async dispatch => {
const config = {
headers: {
'Content-Type': 'application/json'
}
}
try {
const res = await axios.patch(`/api/posts/${id}`, formData, config )
dispatch({
type: EDIT_POST,
payload: res.data
})
dispatch(setAlert('Post Updated', 'success'))
} catch (error) {
dispatch({
type: POST_ERROR,
payload: { msg: error.response.statusText, status: error.response.status }
})
}
}
和减速器:
case EDIT_POST:
return {
...state,
posts: [payload, ...state.posts],
loading: false
}
然后,反应前端部分:
import React, { useState, Fragment } from 'react'
import PropTypes from 'prop-types'
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
import Moment from 'react-moment'
import Alert from '../layout/Alert'
import { addLike, removeLike, editPost, deletePost } from '../../actions/post'
const PostItem = ({
auth,
addLike,
removeLike,
editPost,
deletePost,
post : {
_id,
text,
name,
avatar,
user,
likes,
comments,
date
},
showActions,
}) => {
const [liked, toggleLiked ] = useState(false)
const [editMode, toggleEditMode ] = useState(false)
const [postContent, setPostContent ] = useState(text)
const likeButton = () => {
toggleLiked(!liked)
if (!liked) {
addLike(_id)
} else {
removeLike(_id)
}
}
const editPostButton = () => {
toggleEditMode(!editMode)
}
const onSubmit = (e) => {
e.preventDefault()
editPost(_id, {postContent})
// history.push('/api/posts')
}
return (
<div className="post-item">
<div className="post-item__bio">
<img src={avatar} alt=""/>
<h6>{name}</h6>
</div>
<div>
{ editMode ? (
<Fragment key={_id}>
<Alert />
<form className="form form--edit" onSubmit={onSubmit}>
<textarea
name="text"
cols="30"
rows="5"
placeholder="Edit your post"
value={postContent}
onChange={e => setPostContent(e.target.value)}
required
></textarea>
<input type="submit" className="btn" value="Done!" />
</form>
</Fragment>
):(<p>{postContent}</p>)}
<div className="post-item__meta">
<p className="post-item__meta-item">
<Moment format="YYYY/MM/DD">{date}</Moment>
</p>
{showActions && <Fragment>
{ likes.filter(like => like.user === auth.user._id).length > 0 ? (<div className={ "heart red" } onClick={()=> likeButton()} ></div>) : (<div className={ liked ? "heart is-active": "heart"} onClick={()=> likeButton()}></div>) }
<button type="button" onClick={()=> addLike(_id)} className="post-item__meta-item">
<span>{likes.length > 0 && (
<span className='comment-count'>{likes.length} ♥</span>
)}</span>
</button>
<Link to={`/echelon/posts/${_id}`} className="post-item__meta-item">
View {comments.length > 0 && (
<span className='comment-count'>{comments.length}</span>
)} Comments
</Link>
{!auth.loading && user === auth.user._id && (
<Fragment>
<button type="button" onClick={() => editPostButton()} className="post-item__meta-item">
Edit
</button>
<button type="button" onClick={() => deletePost(_id)} className="post-item__meta-item delete">
×
</button>
</Fragment>
)}
</Fragment>}
</div>
</div>
</div>
)
}
PostItem.defaultProps ={
showActions: true
}
PostItem.propTypes = {
post: PropTypes.object.isRequired,
auth: PropTypes.object.isRequired,
addLike: PropTypes.func.isRequired,
removeLike: PropTypes.func.isRequired,
editPost: PropTypes.func.isRequired,
deletePost: PropTypes.func.isRequired,
}
const mapStateToProps = state => ({
auth: state.auth
})
export default connect(mapStateToProps, { addLike, removeLike, editPost, deletePost } )(PostItem)
import React,{useState,Fragment}来自“React”
从“道具类型”导入道具类型
从“react router dom”导入{Link}
从“react redux”导入{connect}
从“反应时刻”导入时刻
从“../layout/Alert”导入警报
从“../../actions/post”导入{addLike、removeLike、editPost、deletePost}
常数positem=({
啊,,
愚蠢的,
removeLike,
编辑部,
deletePost,
职位:{
_身份证,
文本,
名称
阿凡达
用户,
喜欢,
评论,
日期
},
表演,
}) => {
const[liked,toggleLiked]=useState(false)
常量[editMode,toggleEditMode]=useState(false)
常量[postContent,setPostContent]=useState(文本)
常量likeButton=()=>{
toggleLiked(!liked)
如果(!喜欢){
addLike(_id)
}否则{
removeLike(_id)
}
}
const editPostButton=()=>{
切换editMode(!editMode)
}
const onSubmit=(e)=>{
e、 预防默认值()
编辑文章(_id,{postContent})
//history.push(“/api/posts”)
}
返回(
{name}
{编辑模式(
setPostContent(e.target.value)}
必修的
>
):({postContent})}
{date}
{showActions&&
{likes.filter(like=>like.user===auth.user.\u id).length>0?(likeButton()}>):(likeButton()}>)}
addLike(\u id)}className=“post-item\uu-meta-item”>
{likes.length>0&&(
{likes.length}♥;
)}
查看{comments.length>0&&(
{comments.length}
)}评论
{!auth.loading&&user==auth.user.\u id&&(
editPostButton()}className=“post-item\uuu meta-item”>
编辑
deletePost(\u id)}className=“post-item\uu meta-item delete”>
&时代;
)}
}
)
}
positem.defaultProps={
表演:真的
}
positem.propTypes={
post:PropTypes.object.isRequired,
auth:PropTypes.object.isRequired,
addLike:PropTypes.func.isRequired,
removeLike:PropTypes.func.isRequired,
编辑帖子:PropTypes.func.isRequired,
deletePost:PropTypes.func.isRequired,
}
常量mapStateToProps=状态=>({
auth:state.auth
})
导出默认连接(mapStateToProps、{addLike、removeLike、editPost、deletePost})(PostItem)
问题:
在编辑模式下按下submit按钮后,我通过post链接收到了错误的请求。每隔一段时间,其他按钮或链接都可以正常工作。完成(编辑>完成!通过提交)是唯一不起作用的
我对React和Redux相当陌生,我不确定是哪一步导致了问题。我猜也许这样我们没有通过req.params找到id?那么我怎样才能正确地传递id进行更新呢 你的
onSubmit
在我看来很奇怪editPost
创建一个操作/thunk,但该操作不会被调度。另外,history.push
应该在页面中导航,因此/api
似乎不正确
这可能也会导致您的请求不正确,但我不确定这一点,因为
history.push
不是标准的全局函数。这取决于它的实现。嗨,我现在已经自己解决了这个问题
在React代码中:让我们添加
const formData = {
text: postContent
}
const onSubmit = (e) => {
e.preventDefault()
editPost(_id, formData)
toggleEditMode(!editMode)
}
使用路由器和历史不再是必要的。问题的出现是因为我对州的命名感到困惑。由于我们需要将数据保存到post.text(正如您在后端看到的那样),formData必须是{text:data}。在我的原始代码中,它显示为{postContent:data},这就是它不起作用的原因
此外,为了使所有内容保持最新,我们也需要更改后端,在保存帖子后,我们需要找到所有帖子并重新呈现
post.text = req.body.text
await post.save()
const posts = await Post.find().sort({date: -1})
res.json(posts)
然后我们还需要更换减速器:
case EDIT_POST:
return {
...state,
posts: payload,
loading: false
}
我暂时禁用了
历史记录
,但仍然收到了错误的请求。您所说的操作未被调度是什么意思?editPost
创建了一个期望传递dispatch
的函数。该函数通常在分派时由redux-thunk
中间件调用。但是您没有使用editPost
操作调用dispatch。history.push
不会导致错误的请求错误,这绝对是荒谬的。history.push
确实可以做任何事情,因为它没有定义。我还明确表示,这可能会导致它。从指定的代码来看,根本不清楚为什么要执行axios调用。因此,怀疑回调中唯一的其他函数会导致这种情况并不荒谬。你能做些什么吗?这只是一个糟糕的论点。如果没有