Reputation: 133
Hi everybody I am using reactjs and redux for frontend and I want to create new articles so I created CreateArticle.js as below
import { useDispatch, useSelector } from 'react-redux'
import { unwrapResult } from '@reduxjs/toolkit'
import { addNewArticle } from './managementSlice'
import { selectAccessToken, selectUser } from '../authentications/authenticationsSlice'
import './CreateArticle.scss';
import { selectAllSubjects, fetchSubjects } from '../subjects/subjectsSlice';
import { selectAllTags, fetchTags } from '../tags/tagsSlice';
export const CreateArticle = () => {
const [title, setTitle] = useState('')
const [body, setBody] = useState('')
const [slug, setSlug] = useState('')
const [subjectId, setSubjectId] = useState(0)
const [tags, setTags] = useState([])
const [addRequestStatus, setAddRequestStatus] = useState('idle')
const user = useSelector(selectUser);
const subjects = useSelector(selectAllSubjects)
const allTags = useSelector(selectAllTags)
const subjectStatus = useSelector((state) => state.subjects.status)
const tagStatus = useSelector( (state) => state.tags.status)
const dispatch = useDispatch()
// const onSubjectChanged = (e) => setSubjectId(parseInt(e.target.value))
const onSubjectChanged = (e) => setSubjectId(e.target.value)
const onTitleChanged = (e) => {
setTitle(e.target.value)
setSlug(e.target.value.toLowerCase())}
const onBodyChanged = (e) => {
setBody(e.target.value)
console.log(e.target.value);
}
const onTagsChanged = (e) => {
const selectedOptions = [...e.target.selectedOptions].map(o => parseInt(o.value))
setTags(selectedOptions)
}
const onSaveArticleClicked = async () => {
let article = { Subject:subjectId, Title: title, Body:body, Tags:tags, Slug:slug }
if (user){
try {
setAddRequestStatus('pending')
console.log('addRequestStatus:', addRequestStatus)
const resultAction = await dispatch(
addNewArticle(article)
)
unwrapResult(resultAction)
setTitle('')
setBody('')
setTags([])
setSlug('')
console.log('resultAction:', resultAction)
} catch (err) {
console.error('Failed to save the article: ', err)
} finally {
setAddRequestStatus('idle')
}
}
}
useEffect( () =>
{
if (subjectStatus === 'idle') {
dispatch(fetchSubjects())
}
},
[subjectStatus, dispatch]
)
let subjectsOptions
if (subjectStatus === 'loading') {
subjectsOptions = <div className="loader"> Loading... </div>
} else if (subjectStatus === 'succeeded') {
subjectsOptions = subjects.map((subject) => (
<option key={subject.id} value={subject.id} >
{subject.title}
</option>
))
} else if (subjectStatus === 'error') {
subjectsOptions = <div> Something went wrong </div>
}
useEffect( () =>
{
if (tagStatus === 'idle') {
dispatch(fetchTags())
}
},
[tagStatus, dispatch]
)
let tagsOptions
if (tagStatus === 'loading') {
tagsOptions = <div className="loader"> Loading... </div>
} else if (tagStatus === 'succeeded') {
tagsOptions = allTags.map((tag) => (
<option key={tag.id} value={tag.id} >
{tag.title}
</option>
))
} else if (tagStatus === 'error') {
tagsOptions = <div> error </div>
}
return (
<div className="create-article">
<div className="create-article-head">
</div>
<form className="create-article-form" >
<label htmlFor="article-title">Article Title:</label>
<input
type="text"
className="article-title-input"
id="id-article-title-input"
name="title"
placeholder="What's on your mind?"
value={title}
onChange={onTitleChanged}
/>
<label htmlFor="article-subject">subject:</label>
<select
id="id-subjects-article-select"
className="subjects-article-select"
onChange={onSubjectChanged}>
<option value="">
انتخاب موضوع
</option>
{subjectsOptions}
</select>
<label htmlFor="article-tags">tags:</label>
<select
id="id-tags-article-select"
className="tags-article-select"
onChange={onTagsChanged}
multiple
>
<option value="">
SELECT TAGS
</option>
{tagsOptions}
</select>
<label htmlFor="article-body">Body:</label>
<textarea
className="article-body-textarea"
id="id-article-body-textarea"
name="body"
value={body}
onChange={onBodyChanged}
/>
<button
type="button"
onClick={onSaveArticleClicked}
>
Save Article
</button>
</form>
</div>
)
}
then I created managementSlice.js to send data to server as below:
import {
createSlice,
createAsyncThunk,
createEntityAdapter,
} from '@reduxjs/toolkit'
// import axios from 'axios';
// with below import axios workes correctly
import * as axios from 'axios';
const managementAdapter = createEntityAdapter()
const initialState = managementAdapter.getInitialState({
status: 'idle',
error: null,
})
export const fetchMyArticles = createAsyncThunk('myArticles/fetchMyArticles', async () => {
// const accessToken = useSelector(selectAccessToken);
const accessToken = localStorage.getItem('access_token')
const ARTICLES_PATH = 'http://127.0.0.1:8000/articles_api/v1/management/';
const response = await axios(ARTICLES_PATH,
{ headers: { "Authorization": `Bearer ${accessToken}` }})
const data = response;
console.log( 'fetchMyArticles: ', data)
return response.data
})
export const addNewArticle = createAsyncThunk(
'management/addNewArticle',
async (initialArticle) => {
const accessToken = localStorage.getItem('access_token')
const ARTICLE_CREATE_PATH = 'http://127.0.0.1:8000/articles_api/v1/management/';
console.log("before send new article to server:", initialArticle)
try {
const response = await axios.post(ARTICLE_CREATE_PATH, initialArticle ,
{ headers: {
"Authorization": `Bearer ${accessToken}`,
'Content-Type' : 'application/json; charset=UTF-8',
}})
console.log('what the hell:', response);
} catch (error) {
console.error('erroroo',error.response.data);
}
}
)
const managementSlice = createSlice({
name: 'management',
initialState,
reducers: {},
extraReducers: {
[fetchMyArticles.pending]: (state, action) => {
state.status = 'loading'
},
[fetchMyArticles.fulfilled]: (state, action) => {
state.status = 'succeeded'
// Add any fetched articles to the array
managementAdapter.upsertMany(state, action.payload)
},
[fetchMyArticles.rejected]: (state, action) => {
state.status = 'failed'
state.error = action.payload
},
[addNewArticle.fulfilled]: managementAdapter.addOne,
},
})
export const {
} = managementSlice.actions
export default managementSlice.reducer
export const {
selectAll: selectMyArticles,
selectById: selectMyArticleById,
selectIds: selectMyArticleIds,
} = managementAdapter.getSelectors((state) => state.management)
but after sending request I recieve 400 bad request error. I don't undrestand which part I am doing wrong? My backend is with Django and I tested it with postman, and it is ok when I send data with postman
Upvotes: 1
Views: 1037
Reputation: 13933
I faced the same issue with .NET Web API. It would be an axios request headers/body problem. You should set headers of your post request as:
headers: {
'content-type': 'application/json',
}
Or try sending request body as form-data as:
let formData = new FormData()
formdata.append('name', yourJson)
await axios({
method: 'post',
url: '/your/url',
data: formData,
headers: {
'Content-Type': 'multipart/form-data',
},
})
Upvotes: 1