I am basically new to react and just following a guided project from a YouTube channel.
I am half way in this project.
From app js Form component is called and in Form component when i click on submit it calls createPost()
function in "client/src/actions/posts.js" and the data gets dispatched even though async and await keyword present in createPost()
it is not posting asynchronisingly. It shows error in try block which is in createPost()
Cannot destructure property 'data' of '(intermediate value)' as it is undefined
but inside that createPost() another createPost() is called which is in "client/src/api/index.js" where axios is used to post the data. When i try to console log the response over there in browser console i am getting
status:201
statusText:"Created"
After this when i reloaded the data are posted and it is reflecting in the UI. I believe this is because of async and await keyword not working. In vscode the await keyword present in createPosst()
which is in "client/src/actions/posts.js" gets underlined and shows 'await' has no effect on the type of this expression.
(Please refer createPost() function in "client/src/actions/posts.js").I have attached the code files below . Thank you.
Client Folder Structure
▼ client
> node_modules
> public
▼ src
▼ actions
posts.js
▼ api
index.js
▼ components
▼ Form
Form.js
styles.js
▼ Posts
▼ Post
Post.js
styles.js
Posts.js
styles.js
▼ images
15.png
▼ reducers
index.js
posts.js
App.js
index.js
styles.js
.gitignore
package.json
yarn.lock
client/src/Index.js
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import {reducers} from "./reducers/index";
import App from "./App.js";
const store = createStore(reducers, compose(applyMiddleware(thunk)));
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
client/src/App.js
import React, {useEffect} from "react";
import {
Container,
AppBar,
Typography,
// Groe,
Grid,
Grow,
} from "@material-ui/core";
import {useDispatch} from 'react-redux';
import {getPosts} from './actions/posts';
import Posts from "./components/Posts/Posts.js";
import Form from "./components/Form/Form.js";
import useStyles from './styles';
import img from "./images/15.png";
export default function App() {
const classes = useStyles();
const dispatch = useDispatch();
useEffect(()=>{
dispatch(getPosts());
},[dispatch])
return (
<Container maxwidth="lg">
<AppBar className={classes.appBar} position="static" color="inherit">
<Typography className={classes.heading} varient="h2" align="center">
Memories
</Typography>
<img className={classes.image} src={img} alt="memories" height="60" />
</AppBar>
<Grow in>
<Container>
<Grid
container
justifyContent="space-between"
alignItems="stretch"
spacing={3}
>
<Grid item xs={12} sm={7}>
<Posts />
</Grid>
<Grid item xs={12} sm={4}>
<Form />
</Grid>
</Grid>
</Container>
</Grow>
</Container>
);
}
client/src/actions/posts.js
import * as api from '../api';
export const getPosts = () => async(dispatch)=>{
try{
const {data} = await api.fetchPosts();
dispatch({type:'FETCH_ALL',payload:data});
}catch (error){
console.log(error.message);
}
}
export const createPost = (post) => async(dispatch) =>{
try{
//In vscode when i hoover over the below await keyword it shows like below
//'await' has no effect on the type of this expression.
const {data} = await api.createPost(post)
dispatch({type:'CREATE',payload:data})
}catch (error){
console.log(error.message)
}
}
client/src/api/index.js
import axios from 'axios';
const url = 'http://localhost:5000/posts';
export const fetchPosts = () => axios.get(url);
export const createPost = (newPost) => {
axios.post(url,newPost).then((res)=>console.log(res))};
client/src/components/Form/Form.js
import React, { useState} from "react";
import { TextField, Button, Typography, Paper } from "@material-ui/core";
import useStyles from "./styles";
import FileBase from "react-file-base64";
import { useDispatch } from "react-redux";
import { createPost } from "../../actions/posts";
export default function Form() {
const classes = useStyles();
const dispatch = useDispatch();
const [postData, setPostData] = useState({
creator: "",
title: "",
message: "",
tags: "",
selectedfile: "",
});
const handleSubmit = (e) => {
e.preventDefault();
dispatch(createPost(postData));
};
const clear = () => {};
return (
<Paper className={classes.paper}>
<form
autoComplete="off"
noValidate
className={`${classes.root} ${classes.form}`}
onSubmit={handleSubmit}
>
<Typography variant="h6">creating a Memory</Typography>
<TextField
name="creator"
variant="outlined"
label="Creator"
fullWidth
value={postData.creator}
onChange={(e) =>
setPostData({ ...postData, creator: e.target.value })
}
/>
<TextField
name="title"
variant="outlined"
label="Title"
fullWidth
value={postData.title}
onChange={(e) => setPostData({ ...postData, title: e.target.value })}
/>
<TextField
name="message"
variant="outlined"
label="Message"
fullWidth
value={postData.message}
onChange={(e) =>
setPostData({ ...postData, message: e.target.value })
}
/>
<TextField
name="tags"
variant="outlined"
label="Tags"
fullWidth
value={postData.tags}
onChange={(e) => setPostData({ ...postData, tags: e.target.value })}
/>
<div className={classes.fileInput}>
<FileBase
type="file"
multiple={false}
onDone={({ base64 }) =>
setPostData({ ...postData, selectedFile: base64 })
}
/>
</div>
<Button
className={classes.buttonSubmit}
variant="contained"
color="primary"
size="large"
type="submit"
fullWidth
>
Submit
</Button>
<Button
variant="contained"
color="secondary"
size="small"
onClick={clear}
fullWidth
>
clear
</Button>
</form>
</Paper>
);
}
client/src/reducers/posts.js
export default (posts=[],action) =>{
switch (action.type){
case 'FETCH_ALL':
return action.payload;
case 'CREATE':{
return [...posts,action.payload];}
default:
return posts;
}
}
client/src/reducers/index.js
import { combineReducers } from "redux";
import posts from "./posts";
export const reducers= combineReducers({
posts:posts,
});
Server Folder Structure
▼ server
▼ controllers
posts.js
▼ models
postMessage.js
> node_modukes
▼ routes
posts.js
index.js
package.json
yarn.lock
server/controllers/posts.js
import PostMessage from "../models/postMessage.js";
export const getPosts = async (req, res) => {
try {
const postMessages = await PostMessage.find();
res.status(200).json(postMessages);
} catch (error) {
res.status(400).json({ message: error.message });
}
};
export const createPost = async (req, res) => {
const post = req.body;
const newPost = new PostMessage(post);
try {
await newPost.save();
res.status(201).json(newPost);
} catch {
res.status(409).json({ message: error.message });
}
};
server/models/postMessage.js
import mongoose from 'mongoose';
const postSchema = mongoose.Schema({
title: String,
message: String,
creator: String,
tags: [String],
selectedFile: String,
likeCount: {
type: Number,
default: 0,
},
createdAt: {
type: Date,
default: new Date(),
},
})
var PostMessage = mongoose.model('PostMessage', postSchema);
export default PostMessage;
server/routes/posts.js
import express from "express";
import { getPosts, createPost } from "../controllers/posts.js";
const router = express.Router();
router.get("/", getPosts);
router.post("/", createPost);
export default router;
server/index.js
import express from "express";
import bodyParser from "body-parser";
import mongoose from "mongoose";
import cors from "cors";
import postRoutes from "./routes/posts.js";
const app = express();
app.use(bodyParser.json({ limit: "30mb", extended: true }));
app.use(bodyParser.urlencoded({ limit: "30mb", extended: true }));
app.use(cors());
app.use("/posts", postRoutes);
const CONNECTION_URL ="...(connection url provided correctly in code)";
const PORT = process.env.PORT || 5000;
mongoose
.connect(CONNECTION_URL, { useNewUrlParser: true, useUnifiedTopology: true })
.then(() => app.listen(PORT, () => console.log(`Port:${PORT}`)))
.catch((error) => console.log(error.message));
CodePudding user response:
In your client/src/api/index.js
you didn't return the API response. You need to return the response like this
export const createPost = (newPost) => {
return axios.post(url, newPost).then((res)=> res )
};
or
export const createPost = (newPost) => axios.post(url, newPost);