Состояние обновления Redux с нулевым значением перед фактическими данными

Я отправляю действие, которое должно принимать данные от пользователя и сохранять их в базе данных. Однако, когда я проверяю состояние своих сообщений в редуксе после отправки действия, перед фактическим сообщением к массиву состояния добавляется нулевое значение. Это мешает мне работать с фактическими данными в массиве сообщений. В основном мне интересно, как предотвратить добавление нуля каждый раз, когда я отправляю новое сообщение. Вот соответствующий код фрагменты и изображения.

Почтовый редуктор:

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;

🤔 А знаете ли вы, что...
React Hooks - это механизм, введенный в React 16.8, для управления состоянием компонентов функциональным способом.


51
2

Ответы:

в 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;
  }
};