Answer a question

I want to update data from react by using FormData. When I console.log() Formdata, every key value pair is correct. After dispatch, it graps the updateMainNews and the redux-devtools are telling me: pending, rejected and I get the alert:

localhost:3000 includes undefined.

Because of the answers I get here, I have edited my code, and the error above is gone away. But the update not really works. First I have endless pending and the console throws the error:

state.mainnews.push is not a function

But when I refresh my site, the article is updated. And I have an endless running message in the console:

Tracking Prevention blocked access to storage for .

That is my Formdata, in which is everything correct:

  const onSubmit = (e)=>{
    e.preventDefault();
    const mainnewsData = new FormData();
    mainnewsData.append("ressort", data.ressort);
    mainnewsData.append("theme", data.theme);
    mainnewsData.append("title", data.title);
    mainnewsData.append("content", data.content);
    mainnewsData.append("img", fileData);
   for(let value of mainnewsData){
        console.log(value);
   }
   console.log(id);
   const updateData = {id: id, mainnewsData: mainnewsData}
    dispatch(updateMainNews(updateData));

    return ()=>{
        dispatch(reset());
    }
}

Then it goes to my Slice:

export const updateMainNews = createAsyncThunk("mainNews/update", async (updateData, thunkAPI)=>{
    try{
        const token = thunkAPI.getState().auth.user.accessToken;
        return await mainnewsService.updateMainNews(updateData, token);
    } catch(error){
        const message = (error.response 
            && error.response.data 
            && error.response.data.message) 
            || error.message 
            || error.toString();
        return thunkAPI.rejectWithValue(message);
    }
})

My extraReducer:

 .addCase(updateMainNews.fulfilled, (state, action)=>{
                state.isLoading = false;
                state.isSuccess = true;
                state.mainnews.push(action.payload);
            })

My redux-service:

const updateMainNews = async (updateData, token)=>{
    const config = {
        headers:{
            'Content-Type':'multipart/form-data',
            token: `Bearer ${token}`}
    }
    const response = await axios.put(API_URL + updateData.id, updateData.mainnewsData, config);
    return response.data;
}

The backend:

router.put("/:id", upload.single("img"), verifyTokenAndAuthorization, async (req,res)=>{
    try{
        let updatedMainNews = await MainNews.findById(req.params.id);
        console.log(updatedMainNews);
        //destroy
        await cloudinary.uploader.destroy(updatedMainNews.cloudinary_id);
        //upload
        let result;
        if(req.file){
        result = await cloudinary.uploader.upload(req.file.path, {
            upload_preset: "Mern_redux-practice",
            resource_type: "auto",
        })
        }
        const updatedData = {
            ressort: req.body.ressort || updatedMainNews.ressort,
            theme: req.body.theme || updatedMainNews.theme,
            title: req.body.title || updatedMainNews.title,
            content: req.body.content || updatedMainNews.content,
            cloudinary_id: result.public_id || updatedMainNews.cloudinary_id,
            img: result.secure_url || updatedMainNews.img,
        }
        updatedMainNews = await MainNews.findByIdAndUpdate(req.params.id, updatedData, {
            new:true,
        })

        res.status(200).json(updatedMainNews);
    } catch(error){
        res.status(404)
        throw new Error("Not found");
    }
});

Answers

When you are working with form data you have to send the content-type as well.

When you are passing variables to createAsyncThunk or reducer action you have to pass it as one argument. The way you can do it is by passing an object instead.

dispatch(updateMainNews({id, mainnewsData}))

Then you need to use deconstruct the variables.

export const updateMainNews = createAsyncThunk("mainNews/update", async ({id, mainnewsData}, thunkAPI)=>{
try{
    const token = thunkAPI.getState().auth.user.accessToken;
    return await mainnewsService.updateMainNews(id, mainnewsData, token);
} catch(error){
    const message = (error.response 
        && error.response.data 
        && error.response.data.message) 
        || error.message 
        || error.toString();
    return thunkAPI.rejectWithValue(message);
}

})

Hope this works out for you.

Logo

React社区为您提供最前沿的新闻资讯和知识内容

更多推荐