Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
451 views
in Technique[技术] by (71.8m points)

javascript - React-Redux/mongoDB only one key is undefined in action.payload

In react/redux when retrieving blog api info from mongodb, only the blog.user.name is undefined all other keys are defined. I get TypeError: Cannot read property 'name' of undefined when trying to insert blog.user.name on the page. Once I remove it from the page, there is no error and all other data is shown on the page. Also when I remove it from the page, I can see in devtools that it is defined, so I'm not sure why I'm getting this error. Randomly when I toggle with adding and removing blog.user.name from the page the name will show up. If it does show up, as soon as I refresh I get the TypeError again.

Also I tried to display just blog.user to see what would happen and I got : Error: Objects are not valid as a React child (found: object with keys {id, name, profilePic}). If you meant to render a collection of children, use an array instead.. Which mean it's getting the data but just not showing it?

BlogScreen - frontend component where I'm trying to display blog.user.name

import React, { useEffect } from 'react'
import moment from 'moment'
import { useSelector, useDispatch } from 'react-redux'
import { Card, Row, Col, Alert } from 'react-bootstrap'
import { getBlogDetail } from '../../actions/blogActions'
import Spinner from '../../components/layout/Spinner'

const BlogScreen = ({ match }) => {

    const dispatch = useDispatch()

    const blogDetail = useSelector(state => state.blogDetail)
    const { loading, error, blog } = blogDetail

    useEffect(() => {
        if (!blog || blog._id !== match.params.id) {
            dispatch(getBlogDetail(match.params.id))
        }
    }, [match, dispatch, blog])

    return (
        <>
            {loading && <Spinner />}
            {error && <Alert variant='danger'>{error}</Alert>}
            {blog && (
                <>
                    <div className="blog-main pt-5">
                        <div className="blog-heading text-center">
                            <p className="text-muted font-weight-bold">{moment(new Date(blog.createdAt)).format("ddd MMM DD")} | {blog.user.name}</p>
                            <h3 className="my-5">{blog.title}</h3>
                        </div>
                        <p className="content content-one text-justify">{blog.paragraph1}</p>
                        <div className="blog-image my-4">
                            <img src={blog.primaryImage} alt="" />
                        </div>
                        <p className="content content-two text-justify">{blog.paragraph2}</p>
                        <div className="blog-image my-4">
                            <img src={blog.secondaryImage} alt="" />
                        </div>
                        <p className="content content-three text-justify">{blog.paragraph3}</p>
                    </div>
                    <div className="more-like">
                        <h3 className="mb-4">More Like This</h3>
                        <Row>
                            <Col sm="12" md="4" className="mb-3">
                                <Card className="h-100">
                                    <Card.Img variant="top" src="/images/connect.jpg" />
                                    <Card.Body>
                                        <Card.Title>Scheduling: Planning Your Day To Be More Productive</Card.Title>
                                        <Card.Text>Wed Jun 4 | Tania Reece</Card.Text>
                                    </Card.Body>
                                </Card>
                            </Col>
                            <Col sm="12" md="4" className="mb-3">
                                <Card className="h-100">
                                    <Card.Img variant="top" src="/images/connect.jpg" />
                                    <Card.Body>
                                        <Card.Title>Scheduling: Planning Your Day To Be More Productive</Card.Title>
                                        <Card.Text>Wed Jun 4 | Tania Reece</Card.Text>
                                    </Card.Body>
                                </Card>
                            </Col>
                            <Col sm="12" md="4" className="mb-3">
                                <Card className="h-100">
                                    <Card.Img variant="top" src="/images/connect.jpg" />
                                    <Card.Body>
                                        <Card.Title>Scheduling: Planning Your Day To Be More Productive</Card.Title>
                                        <Card.Text>Wed Jun 4 | Tania Reece</Card.Text>
                                    </Card.Body>
                                </Card>
                            </Col>
                        </Row>
                    </div>
                </>
            )}
        </>
    )
}

export default BlogScreen

Blog Action and Reducer

//action
export const getBlogDetail = (id) => async (dispatch) => {
    try {
        dispatch({ type: BLOG_DETAIL_REQUEST })
        const { data } = await axios.get(`/api/blogs/${id}`)
        dispatch({
            type: BLOG_DETAIL_SUCCESS,
            payload: data
        })

    } catch (error) {
        dispatch({
            type: BLOG_DETAIL_FAIL,
            payload: error.response && error.response.data.message
                ? error.response.data.message
                : error.message
        })
    }
}

//reducer
export const blo
/gDetailReducer = (state = { blog: {} }, action) => {
    switch (action.type) {
        case BLOG_DETAIL_REQUEST:
            return { ...state, loading: true }
        case BLOG_DETAIL_SUCCESS:
            return {
                loading: false,
                blog: action.payload
            }
        case BLOG_DETAIL_FAIL:
            return { loading: false, error: action.payload }
        default:
            return state
    }
}

reducer store

import { createStore, applyMiddleware, combineReducers } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunk from 'redux-thunk';

import { blogDetailReducer, blogsFeaturedListReducer, blogsListReducer, blogsRecentListReducer } from './reducers/blogReducers'

// Reducers 
const reducer = combineReducers({
    blogList: blogsListReducer,
    blogFeaturedList: blogsFeaturedListReducer,
    blogRecentList: blogsRecentListReducer,
    blogDetail: blogDetailReducer,
})

const initialState = {

}

const middleware = [thunk];

const store = createStore(
    reducer,
    initialState,
    composeWithDevTools(applyMiddleware(...middleware))
)

export default store;

BlogModel

import mongoose from 'mongoose';
const blogSchema = mongoose.Schema({
    title: {
        type: String,
        required: true
    },
    user:
    {
        id: {
            type: mongoose.Schema.Types.ObjectId,
            required: true,
            ref: 'User'
        },
        name: String,
        profilePic: String,
    },
    primaryImage: {
        type: String,
        required: true
    },
    secondaryImage: {
        type: String,
        required: true
    },
    category: {
        type: String,
        required: true
    },
    reviews: [reviewSchema],
    rating: {
        type: Number,
        required: true,
        default: 0,
    },
    numReviews: {
        type: Number,
        required: true,
        default: 0,
    },
    featured: {
        type: Boolean,
        required: true,
        default: false
    },
    paragraph1: {
        type: String,
        required: true
    },
    paragraph2: {
        type: String,
        required: true
    },
    paragraph3: {
        type: String,
        required: true
    },
}, {
    timestamps: true
})

const Blog = mongoose.model('Blog', blogSchema)

export default Blog

blogController

export const getBlogById = async (req, res) => {

    try {
        if (mongoose.Types.ObjectId.isValid(req.params.id)) {
            const blog = await Blog.findById(req.params.id)

            if (!blog) {
                return res.status(404).json({ message: 'Blog not Found' })
            } else {
                res.json(blog)
            }
        } else {
            return res.status(404).json({ message: 'Invalid ID' })
        }

    } catch (error) {
        res.status(500).json({ message: 'Server Error' })
    }

}

Blog Routes

import express from 'express'
const router = express.Router()
import { getBlogs, getBlogById, updateBlog, updateUserBlog, createBlog, deleteBlog, createBlogReview, getFeaturedBlogs, getRecentBlogs } from '../controllers/blogControllers.js';
import { admin, protect } from '../middleware/authMiddleware.js'


router.route('/').get(getBlogs).post(protect, createBlog)
router.route('/recent').get(getRecentBlogs)
// router.route('/top').get(getTopRatedBlogs)
router.route('/featured').get(getFeaturedBlogs)
// router.route('/category/:category').get(getBlogsByCategory)
router.route('/user/:id').put(protect, updateUserBlog)
router
    .route('/:id')
    .get(getBlogById)
    .delete(protect, deleteBlog)
    .put(protect, admin, updateBlog)
router.route('/:id/reviews').post(protect, createBlogReview)

export default router;

Server.js

import express from 'express'
import cors from 'cors'
import dotenv from 'dotenv'
import connectDB from './config/db.js'
import userRoutes from './routes/userRoutes.js'
import blogRoutes from './routes/blogRoutes.js'

dotenv.config()
connectDB()

const app = express()
app.use(cors({ credentials: true, origin: "http://localhost:3000" })) 
app.use(express.json())


app.use('/api/users', userRoutes)
app.use('/api/blogs', blogRoutes)


app.get('/', (req, res) => {
    res.send('Api is running....')
})

const PORT = process.env.PORT || 5000

app.listen(PORT, console.log(`Server is running on port ${PORT}`))

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

can you try with { blog.user && blog.user.name} in the BlogScreen component


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...