如何在 redux 中使用 axios 库将 post 数据发送到 API 服务器
How to post data to an API server using axios library in redux
我有一个 redux 表单,我正在从中检索数据并尝试 post 它到我的 API server.The 我的 redux-form 代码如下:
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { createPosts } from '../actions/posts_action';
class CreatePost extends Component {
constructor() {
super();
this.state = {
selectValue : ''
};
this.renderCategory = this.renderCategory.bind(this);
}
renderField(field) {
return(
<div className="title-design">
<label className="label-design"> {field.label} </label>
<input
type="text"
className="title-input"
{...field.input}
/>
<div className="text-help has-danger">
{field.meta.touched ? field.meta.error : ''}
</div>
</div>
);
}
renderCategory(field) {
return(
<div className="title-design">
<label className="label-design">{field.label} </label>
<Field name="category" className="title-input" component="select">
<option></option>
<option value="react">React</option>
<option value="redux">Redux</option>
<option value="udacity">Udacity</option>
</Field>
<div className="text-help has-danger">
{field.meta.touched ? field.meta.error : ''}
</div>
</div>
);
}
onSubmit(values) {
this.props.createPosts(values, () => {
this.props.history.push('/');
});
}
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<Field
label="Title for Post"
name="title"
component={this.renderField}
/>
<Field
label="Post Content"
name="body"
component={this.renderField}
/>
<Field
label="Category"
name="category"
component={this.renderCategory}
/>
<button type="submit" className="btn btn-primary">Submit</button>
<Link to="/">
<button className="cancel-button">Cancel</button>
</Link>
</form>
);
}
}
function validate(values) {
const errors = {} ;
if (!values.title) {
errors.title = "Enter a title";
}
if (!values.body) {
errors.body = "Enter some content";
}
if(!values.category) {
errors.category = "Please select a category";
}
return errors;
}
export default reduxForm({
validate : validate, //validate
form : 'CreatePostForm'
})(
connect(null,{ createPosts })(CreatePost)
);
我的 Action creator 用于 posting 数据到 API 服务器是:
//Action Creator for creating posts
export function createPosts(values, callback) {
const request = axios.post(`${API}/posts`,values,{headers})
.then(() => callback());
console.log(request);
return dispatch => {
return request.then(({data}) => {
dispatch({
type: CREATE_POST,
payload: data
})
})
}
}
我用于创建 post 的 reducer 是:
import _ from 'lodash';
import { FETCH_POSTS, FETCH_POST, CREATE_POST } from '../actions/posts_action';
export default function(state = {}, action) {
switch (action.type) {
case FETCH_POST:
// const post = action.payload.data;
// const newState = { ...state, };
// newState[post.id] = post;
// return newState;
return {...state, [action.payload.id]: action.payload};
case FETCH_POSTS:
return {posts: { ...state.posts, ...action.payload }};
case CREATE_POST:
return {posts: { ...state, ...action.payload}};
default:
return state;
}
}
我将所有减速器组合在一起的索引文件是:
import { combineReducers } from 'redux';
import PostReducer from './PostsReducer';
import { reducer as formReducer} from 'redux-form';
import CategoriesReducer from './CategoriesReducer';
const rootReducer = combineReducers({
posts: PostReducer,
categories: CategoriesReducer,
form : formReducer
});
export default rootReducer;
现在我面临的问题是,当我尝试提交我的表单数据时,出现如下屏幕截图所示的错误:
任何人都可以指导我做错了什么以及如何继续吗?
编辑 1 整个项目的代码 index.js 文件如下:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { BrowserRouter, Route } from 'react-router-dom';
import thunk from 'redux-thunk';
import './index.css';
import App from './App';
import reducers from './reducers/index.js'
import Posts from './components/posts_index';
import CreatePost from './components/new_post';
import PostDetail from './components/post_detail';
import CategoryView from './components/category';
import { compose } from 'redux';
//const createStoreWithMiddleware = createStore(reducers,applyMiddleware(thunk));
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const createStoreWithMiddleware = createStore(reducers, composeEnhancers(applyMiddleware(thunk)));
ReactDOM.render(
<Provider store={createStoreWithMiddleware}>
<BrowserRouter>
<div>
<Route path="/new" component={CreatePost} />
<Route path="/posts/:id" component={PostDetail} />
<Route exact path="/" component={Posts} />
<Route path="/:category/posts" component={CategoryView} />
</div>
</BrowserRouter>
</Provider> , document.getElementById('root'));
编辑 2:
我还在下面为 API 服务器添加文件:
const clone = require('clone')
let db = {}
const defaultData = {
"8xf0y6ziyjabvozdd253nd": {
id: '8xf0y6ziyjabvozdd253nd',
timestamp: 1467166872634,
title: 'Udacity is the best place to learn React',
body: 'Everyone says so after all.',
author: 'thingtwo',
category: 'react',
voteScore: 6,
deleted: false,
commentCount: 2
},
"6ni6ok3ym7mf1p33lnez": {
id: '6ni6ok3ym7mf1p33lnez',
timestamp: 1468479767190,
title: 'Learn Redux in 10 minutes!',
body: 'Just kidding. It takes more than 10 minutes to learn technology.',
author: 'thingone',
category: 'redux',
voteScore: -5,
deleted: false,
commentCount: 0
}
}
function getData (token) {
let data = db[token]
if (data == null) {
data = db[token] = clone(defaultData)
}
return data
}
function getByCategory (token, category) {
return new Promise((res) => {
let posts = getData(token)
let keys = Object.keys(posts)
let filtered_keys = keys.filter(key => posts[key].category === category && !posts[key].deleted)
res(filtered_keys.map(key => posts[key]))
})
}
function get (token, id) {
return new Promise((res) => {
const posts = getData(token)
res(
posts[id].deleted
? {}
: posts[id]
)
})
}
function getAll (token) {
return new Promise((res) => {
const posts = getData(token)
let keys = Object.keys(posts)
let filtered_keys = keys.filter(key => !posts[key].deleted)
res(filtered_keys.map(key => posts[key]))
})
}
function add (token, post) {
return new Promise((res) => {
let posts = getData(token)
posts[post.id] = {
id: post.id,
timestamp: post.timestamp,
title: post.title,
body: post.body,
author: post.author,
category: post.category,
voteScore: 1,
deleted: false,
commentCount: 0
}
res(posts[post.id])
})
}
function vote (token, id, option) {
return new Promise((res) => {
let posts = getData(token)
post = posts[id]
switch(option) {
case "upVote":
post.voteScore = post.voteScore + 1
break
case "downVote":
post.voteScore = post.voteScore - 1
break
default:
console.log(`posts.vote received incorrect parameter: ${option}`)
}
res(post)
})
}
function disable (token, id) {
return new Promise((res) => {
let posts = getData(token)
posts[id].deleted = true
res(posts[id])
})
}
function edit (token, id, post) {
return new Promise((res) => {
let posts = getData(token)
for (prop in post) {
posts[id][prop] = post[prop]
}
res(posts[id])
})
}
function incrementCommentCounter(token, id, count) {
const data = getData(token)
if (data[id]) {
data[id].commentCount += count
}
}
module.exports = {
get,
getAll,
getByCategory,
add,
vote,
disable,
edit,
getAll,
incrementCommentCounter
}
更新:为动作创建者尝试这种格式。 :
export function createPosts(values, callback) {
return dispatch => { //return function
return axios.post(`${API}/posts`,values,{headers}) //return post request response
.then((data) => { //pass data in as a parameter, call the callback, dispatch the action.
callback();
dispatch({
type: CREATE_POST,
payload: data
})
})
}
}
我有一个 redux 表单,我正在从中检索数据并尝试 post 它到我的 API server.The 我的 redux-form 代码如下:
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import { createPosts } from '../actions/posts_action';
class CreatePost extends Component {
constructor() {
super();
this.state = {
selectValue : ''
};
this.renderCategory = this.renderCategory.bind(this);
}
renderField(field) {
return(
<div className="title-design">
<label className="label-design"> {field.label} </label>
<input
type="text"
className="title-input"
{...field.input}
/>
<div className="text-help has-danger">
{field.meta.touched ? field.meta.error : ''}
</div>
</div>
);
}
renderCategory(field) {
return(
<div className="title-design">
<label className="label-design">{field.label} </label>
<Field name="category" className="title-input" component="select">
<option></option>
<option value="react">React</option>
<option value="redux">Redux</option>
<option value="udacity">Udacity</option>
</Field>
<div className="text-help has-danger">
{field.meta.touched ? field.meta.error : ''}
</div>
</div>
);
}
onSubmit(values) {
this.props.createPosts(values, () => {
this.props.history.push('/');
});
}
render() {
const { handleSubmit } = this.props;
return (
<form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
<Field
label="Title for Post"
name="title"
component={this.renderField}
/>
<Field
label="Post Content"
name="body"
component={this.renderField}
/>
<Field
label="Category"
name="category"
component={this.renderCategory}
/>
<button type="submit" className="btn btn-primary">Submit</button>
<Link to="/">
<button className="cancel-button">Cancel</button>
</Link>
</form>
);
}
}
function validate(values) {
const errors = {} ;
if (!values.title) {
errors.title = "Enter a title";
}
if (!values.body) {
errors.body = "Enter some content";
}
if(!values.category) {
errors.category = "Please select a category";
}
return errors;
}
export default reduxForm({
validate : validate, //validate
form : 'CreatePostForm'
})(
connect(null,{ createPosts })(CreatePost)
);
我的 Action creator 用于 posting 数据到 API 服务器是:
//Action Creator for creating posts
export function createPosts(values, callback) {
const request = axios.post(`${API}/posts`,values,{headers})
.then(() => callback());
console.log(request);
return dispatch => {
return request.then(({data}) => {
dispatch({
type: CREATE_POST,
payload: data
})
})
}
}
我用于创建 post 的 reducer 是:
import _ from 'lodash';
import { FETCH_POSTS, FETCH_POST, CREATE_POST } from '../actions/posts_action';
export default function(state = {}, action) {
switch (action.type) {
case FETCH_POST:
// const post = action.payload.data;
// const newState = { ...state, };
// newState[post.id] = post;
// return newState;
return {...state, [action.payload.id]: action.payload};
case FETCH_POSTS:
return {posts: { ...state.posts, ...action.payload }};
case CREATE_POST:
return {posts: { ...state, ...action.payload}};
default:
return state;
}
}
我将所有减速器组合在一起的索引文件是:
import { combineReducers } from 'redux';
import PostReducer from './PostsReducer';
import { reducer as formReducer} from 'redux-form';
import CategoriesReducer from './CategoriesReducer';
const rootReducer = combineReducers({
posts: PostReducer,
categories: CategoriesReducer,
form : formReducer
});
export default rootReducer;
现在我面临的问题是,当我尝试提交我的表单数据时,出现如下屏幕截图所示的错误:
任何人都可以指导我做错了什么以及如何继续吗?
编辑 1 整个项目的代码 index.js 文件如下:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { BrowserRouter, Route } from 'react-router-dom';
import thunk from 'redux-thunk';
import './index.css';
import App from './App';
import reducers from './reducers/index.js'
import Posts from './components/posts_index';
import CreatePost from './components/new_post';
import PostDetail from './components/post_detail';
import CategoryView from './components/category';
import { compose } from 'redux';
//const createStoreWithMiddleware = createStore(reducers,applyMiddleware(thunk));
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const createStoreWithMiddleware = createStore(reducers, composeEnhancers(applyMiddleware(thunk)));
ReactDOM.render(
<Provider store={createStoreWithMiddleware}>
<BrowserRouter>
<div>
<Route path="/new" component={CreatePost} />
<Route path="/posts/:id" component={PostDetail} />
<Route exact path="/" component={Posts} />
<Route path="/:category/posts" component={CategoryView} />
</div>
</BrowserRouter>
</Provider> , document.getElementById('root'));
编辑 2:
我还在下面为 API 服务器添加文件:
const clone = require('clone')
let db = {}
const defaultData = {
"8xf0y6ziyjabvozdd253nd": {
id: '8xf0y6ziyjabvozdd253nd',
timestamp: 1467166872634,
title: 'Udacity is the best place to learn React',
body: 'Everyone says so after all.',
author: 'thingtwo',
category: 'react',
voteScore: 6,
deleted: false,
commentCount: 2
},
"6ni6ok3ym7mf1p33lnez": {
id: '6ni6ok3ym7mf1p33lnez',
timestamp: 1468479767190,
title: 'Learn Redux in 10 minutes!',
body: 'Just kidding. It takes more than 10 minutes to learn technology.',
author: 'thingone',
category: 'redux',
voteScore: -5,
deleted: false,
commentCount: 0
}
}
function getData (token) {
let data = db[token]
if (data == null) {
data = db[token] = clone(defaultData)
}
return data
}
function getByCategory (token, category) {
return new Promise((res) => {
let posts = getData(token)
let keys = Object.keys(posts)
let filtered_keys = keys.filter(key => posts[key].category === category && !posts[key].deleted)
res(filtered_keys.map(key => posts[key]))
})
}
function get (token, id) {
return new Promise((res) => {
const posts = getData(token)
res(
posts[id].deleted
? {}
: posts[id]
)
})
}
function getAll (token) {
return new Promise((res) => {
const posts = getData(token)
let keys = Object.keys(posts)
let filtered_keys = keys.filter(key => !posts[key].deleted)
res(filtered_keys.map(key => posts[key]))
})
}
function add (token, post) {
return new Promise((res) => {
let posts = getData(token)
posts[post.id] = {
id: post.id,
timestamp: post.timestamp,
title: post.title,
body: post.body,
author: post.author,
category: post.category,
voteScore: 1,
deleted: false,
commentCount: 0
}
res(posts[post.id])
})
}
function vote (token, id, option) {
return new Promise((res) => {
let posts = getData(token)
post = posts[id]
switch(option) {
case "upVote":
post.voteScore = post.voteScore + 1
break
case "downVote":
post.voteScore = post.voteScore - 1
break
default:
console.log(`posts.vote received incorrect parameter: ${option}`)
}
res(post)
})
}
function disable (token, id) {
return new Promise((res) => {
let posts = getData(token)
posts[id].deleted = true
res(posts[id])
})
}
function edit (token, id, post) {
return new Promise((res) => {
let posts = getData(token)
for (prop in post) {
posts[id][prop] = post[prop]
}
res(posts[id])
})
}
function incrementCommentCounter(token, id, count) {
const data = getData(token)
if (data[id]) {
data[id].commentCount += count
}
}
module.exports = {
get,
getAll,
getByCategory,
add,
vote,
disable,
edit,
getAll,
incrementCommentCounter
}
更新:为动作创建者尝试这种格式。 :
export function createPosts(values, callback) {
return dispatch => { //return function
return axios.post(`${API}/posts`,values,{headers}) //return post request response
.then((data) => { //pass data in as a parameter, call the callback, dispatch the action.
callback();
dispatch({
type: CREATE_POST,
payload: data
})
})
}
}