Я отправляю действие, которое должно принимать данные от пользователя и сохранять их в базе данных. Однако, когда я проверяю состояние своих сообщений в редуксе после отправки действия, перед фактическим сообщением к массиву состояния добавляется нулевое значение. Это мешает мне работать с фактическими данными в массиве сообщений. В основном мне интересно, как предотвратить добавление нуля каждый раз, когда я отправляю новое сообщение. Вот соответствующий код фрагменты и изображения.
Почтовый редуктор:
import { enableAllPlugins, produce } from 'immer';
enableAllPlugins();
const initialState = {
posts: [],
loading: false,
error: false,
uploading: false,
};
const postReducer = produce((draftstate, action = {}) => {
switch (action.type) {
case 'UPLOAD_START':
draftstate.loading = true;
draftstate.error = false;
case 'UPLOAD_SUCCESS':
draftstate.posts.push(action.data);
draftstate.uploading = false;
draftstate.error = false;
case 'UPLOAD_FAIL':
draftstate.uploading = false;
draftstate.error = true;
default:
return draftstate;
}
}, initialState);
export default postReducer;
Загрузить сообщение действие:
export const uploadPost = (data) => async (dispatch) => {
dispatch({ type: 'UPLOAD_START' });
try {
const newPost = await UploadApi.uploadPost(data);
console.info('new post before', newPost);
dispatch({ type: 'UPLOAD_SUCCESS', data: newPost.data });
} catch (error) {
console.info(error);
dispatch({ type: 'UPLOAD_FAIL' });
}
};
Поделиться Почтовый индекс:
import React, { useState, useRef } from "react";
import ProfileImage from "../../img/profileImg.jpg";
import "./PostShare.css";
import { UilScenery } from "@iconscout/react-unicons";
import { UilPlayCircle } from "@iconscout/react-unicons";
import { UilLocationPoint } from "@iconscout/react-unicons";
import { UilSchedule } from "@iconscout/react-unicons";
import { UilTimes } from "@iconscout/react-unicons";
import { useSelector, useDispatch } from "react-redux";
import { uploadImage, uploadPost } from "../../actions/uploadAction";
const PostShare = () => {
const loading = useSelector((state) => state.postReducer.uploading);
const [image, setImage] = useState(null);
const imageRef = useRef();
const desc = useRef();
const dispatch = useDispatch();
const { user } = useSelector((state) => state.authReducer.authData);
// handle Image Change
const onImageChange = (event) => {
if (event.target.files && event.target.files[0]) {
let img = event.target.files[0];
setImage(img);
}
};
const reset = () => {
setImage(null);
desc.current.value = "";
};
const handleSubmit = async (e) => {
e.preventDefault();
const newPost = {
userId: user._id,
desc: desc.current.value,
};
if (image) {
const data = new FormData();
const filename = Date.now() + image.name;
data.append("name", filename);
data.append("file", image);
newPost.image = filename;
console.info(newPost);
try {
dispatch(uploadImage(data));
} catch (error) {
console.info(error);
}
}
dispatch(uploadPost(newPost));
reset();
};
return (
<div>
<div className = "PostShare">
<img src = {ProfileImage} alt = "" />
<div>
<input
ref = {desc}
required
type = "text"
placeholder = "What's happening"
/>
<div className = "postOptions">
<div
className = "option"
style = {{ color: "var(--photo)" }}
onClick = {() => imageRef.current.click()}
>
<UilScenery />
Photo
</div>
<div className = "option" style = {{ color: "var(--video" }}>
<UilPlayCircle />
Video
</div>
<div className = "option" style = {{ color: "var(--location)" }}>
<UilLocationPoint />
Location
</div>
<div className = "option" style = {{ color: "var(--shedule)" }}>
<UilSchedule />
Schedule
</div>
<button
className = "button ps-button"
onClick = {handleSubmit}
disabled = {loading}
>
{loading ? "Uploading..." : "Share"}
</button>
<div style = {{ display: "none" }}>
<input
type = "file"
name = "myImage"
ref = {imageRef}
onChange = {onImageChange}
/>
</div>
</div>
{image && (
<div className = "previewImage">
<UilTimes onClick = {() => setImage(null)} />
<img src = {URL.createObjectURL(image)} alt = "" />
</div>
)}
</div>
</div>
</div>
);
};
export default PostShare;
Я был бы рад предоставить любую другую информацию, если это поможет.
Обновление с другими частями кода:
Диспетчер RETRIEVING_SUCCESS:
import * as PostApi from '../api/PostRequest';
export const getTimelinePosts = (id) => async (dispatch) => {
dispatch({ type: 'RETRIEVING_START' });
try {
const { data } = await PostApi.getTimelinePosts(id);
dispatch({ type: 'RETRIEVING_SUCCESS', data: data });
} catch (error) {
dispatch({ type: 'RETRIEVING_FAIL' });
console.info(error);
}
};
Использование getTimelinePosts:
import React, { useEffect } from 'react';
import './Posts.css';
import { PostsData } from '../../Data/PostsData';
import { useDispatch, useSelector } from 'react-redux';
import { getTimelinePosts } from '../../actions/postAction';
import Post from '../Post/Post';
const Posts = () => {
const dispatch = useDispatch();
const { user } = useSelector((state) => state.authReducer.authData);
let { posts, loading } = useSelector((state) => state.postReducer);
console.info('posts content', posts);
useEffect(() => {
dispatch(getTimelinePosts(user._id));
}, []);
return (
<div className = "Posts">
{/* {posts.map((post, id) => {
return <Post data = {post} id = {id}></Post>;
})} */}
</div>
);
};
export default Posts;
поскольку data
поступает прямо из API, вам следует проверить документацию, если ответ допускает значения null
или способы его фильтрации. Если нет, быстрый data.filter(d => d !== null)
должен помочь в редукторе.
@ДжозефД. Да, это работает! Я все еще нахожу странным, как нулевые значения добавляются к массиву перед самими данными, ха-ха. Спасибо за вашу помощь.
в postReducer давайте удалим значение по умолчанию в операторе switch, оно нам не нужно в редюсере, потому что сюда придут другие действия, и код заставит все состояния возвращать начальное состояние.
Я так сделал, но это не помогло решить проблему
Хорошо, я нашел решение для нулевых записей в моем массиве сообщений. Хотя я не уверен, почему это работает, он только добавляет фактические сообщения в массив сообщений и не содержит нулевой записи. Все, что мне нужно было сделать, это изменить способ обновления состояния моего редуктора. Сначала я использовал immer, но не больше. Вот код:
const postReducer = (
state = { posts: [], loading: false, error: false, uploading: false },
action
) => {
switch (action.type) {
case 'UPLOAD_START':
return { ...state, uploading: true, error: false };
case 'UPLOAD_SUCCESS':
return {
...state,
posts: [action.data, ...state.posts],
uploading: false,
error: false,
};
case 'UPLOAD_FAIL':
return { ...state, uploading: false, error: true };
default:
return state;
}
};
@ДжозефД. просто сделал