无法在 react-redux 中异步 post
Not Able to post asynchronously in react-redux
我基本上是新手,只是关注 YouTube 频道的指导项目。
我在这个项目中进行了一半。
从应用程序调用 js Form 组件,当我单击提交时在 Form 组件中,它调用“client/src/actions/posts.js”中的 createPost()
函数,即使 [=24 中存在 async 和 await 关键字,数据也会被调度=] 它不是 post 异步的。它在 createPost()
中的 try 块中显示错误
Cannot destructure property 'data' of '(intermediate value)' as it is
undefined
但在 createPost() 内部调用了另一个 createPost(),它位于“client/src/api/index.js”中,其中 axios 用于 post 数据。当我尝试在浏览器控制台中控制台记录那里的响应时,我得到
status:201
statusText:"Created"
在此之后,当我重新加载数据时 posted,它反映在 UI 中。我相信这是因为 async 和 await 关键字不起作用。在 vscode 中 createPosst()
中出现的 await 关键字在“client/src/actions/posts.js”中带有下划线并显示 'await' has no effect on the type of this expression.
(请参考“[=63=”中的 createPost() 函数.js").我附上了下面的代码文件。谢谢。
客户端文件夹结构
▼ 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
▼ 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));
在您的 client/src/api/index.js
中,您没有 return API 响应。你需要return这样的回应
export const createPost = (newPost) => {
return axios.post(url, newPost).then((res)=> res )
};
或
export const createPost = (newPost) => axios.post(url, newPost);
我基本上是新手,只是关注 YouTube 频道的指导项目。
我在这个项目中进行了一半。
从应用程序调用 js Form 组件,当我单击提交时在 Form 组件中,它调用“client/src/actions/posts.js”中的 createPost()
函数,即使 [=24 中存在 async 和 await 关键字,数据也会被调度=] 它不是 post 异步的。它在 createPost()
Cannot destructure property 'data' of '(intermediate value)' as it is undefined
但在 createPost() 内部调用了另一个 createPost(),它位于“client/src/api/index.js”中,其中 axios 用于 post 数据。当我尝试在浏览器控制台中控制台记录那里的响应时,我得到
status:201
statusText:"Created"
在此之后,当我重新加载数据时 posted,它反映在 UI 中。我相信这是因为 async 和 await 关键字不起作用。在 vscode 中 createPosst()
中出现的 await 关键字在“client/src/actions/posts.js”中带有下划线并显示 'await' has no effect on the type of this expression.
(请参考“[=63=”中的 createPost() 函数.js").我附上了下面的代码文件。谢谢。
客户端文件夹结构
▼ 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
▼ 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));
在您的 client/src/api/index.js
中,您没有 return API 响应。你需要return这样的回应
export const createPost = (newPost) => {
return axios.post(url, newPost).then((res)=> res )
};
或
export const createPost = (newPost) => axios.post(url, newPost);