Mi proyecto actual permite a un usuario ingresar algún título y descripción, y envía una acción apropiada. Parece que funciona bien, ya que muestra create_post_request, seguido de create_post_success con el objeto posterior recién creado devuelto desde la llamada API. Sin embargo, también se adjunta un error que dice "TypeError: State.posts no es iterable". Tengo un estado inicial que es un objeto que tiene el campo de publicaciones establecido en una matriz vacía inicialmente. Aquí hay algunos fragmentos de código.

PostsReducer.js

import {
    FETCH_POSTS_REQUEST,
    FETCH_POSTS_SUCCESS,
    FETCH_POSTS_FAILURE,
    CREATE_POST_REQUEST,
    CREATE_POST_SUCCESS,
    CREATE_POST_FAILURE
} from "./postsConstants";

const INITIAL_STATE = {
    loading: false,
    posts: [],
    error: '',
};

export const postsReducer = (state = INITIAL_STATE, action) => {
    switch (action.type) {
        case FETCH_POSTS_REQUEST:
            return {
                ...state,
                loading: true,
            }
        case FETCH_POSTS_SUCCESS:
            return {
                ...state,
                loading: false,
                posts: action.payload,
                error: '',
            }
        case FETCH_POSTS_FAILURE:
            return {
                ...state,
                loading: false,
                error: action.payload,
            }
        case CREATE_POST_REQUEST:
            return {
                ...state,
                loading: true,
            }
        case CREATE_POST_SUCCESS:
            return {
                ...state,
                loading: false,
                error: '',
                posts: [...state.posts, action.payload],
            }
        case CREATE_POST_FAILURE:
            return {
                ...state,
                loading: false,
                error: action.payload,
            }
        default: return state;
    }
};

PostsActions.js

import {
    FETCH_POSTS_REQUEST,
    FETCH_POSTS_SUCCESS,
    FETCH_POSTS_FAILURE,
    CREATE_POST_REQUEST,
    CREATE_POST_SUCCESS,
    CREATE_POST_FAILURE
} from "./postsConstants";
import * as api from '../../api/posts';

export const fetchPosts = () => {
    return async (dispatch) => {
        try {
            dispatch({
                type: FETCH_POSTS_REQUEST
            });
            const { data } = await api.fetchPosts();
            dispatch({
                type: FETCH_POSTS_SUCCESS,
                payload: data
            });
        } catch (error) {
            dispatch({
                type: FETCH_POSTS_FAILURE,
                payload: error.message
            });
        }
    }
};

export const createPost = (post) => {
    return async (dispatch) => {
        try {
            dispatch({
                type: CREATE_POST_REQUEST
            });
            const { data } = await api.createPost(post);
            dispatch({
                type: CREATE_POST_SUCCESS,
                payload: data
            });
        } catch (error) {
            dispatch({
                type: CREATE_POST_FAILURE,
                payload: error.message
            });
        }
    }
};

Compone.js (el usuario ingresa el título y las descripciones de publicaciones)

import React from 'react';
import { Container, Typography, Button, TextField } from '@material-ui/core';
import { useFormik } from 'formik';
import * as yup from 'yup';
import { useDispatch } from "react-redux";
import { createPost } from "../../redux/index";
import { useHistory } from "react-router-dom";

import useStyles from './styles';

// validation schema
const validationSchema = yup.object({
    title: yup
        .string('Enter a title.')
        .required('A title is required.'),
    description: yup
        .string('Enter a post description.')
        .required('Post description is required.'),
});

function Compose() {;
    const classes = useStyles();
    const dispatch = useDispatch();
    const history = useHistory();

    const formik = useFormik({
        initialValues: {
            title: '',
            description: ''
        },
        validationSchema: validationSchema,
        onSubmit: (values) => {
            dispatch(createPost(values));
        }
    });

    return (
        <Container className={classes.container} maxWidth="lg" >
            <form className={classes.form} autoComplete="off" onSubmit={formik.handleSubmit}>
                <Typography
                    className={classes.header}
                    variant="h3"
                >
                    Compose
                </Typography>
                <Typography
                    className={classes.postLabel}
                    variant="h6"
                >
                    Title
                </Typography>
                <TextField 
                    className={classes.postTitle}
                    name="title"
                    variant="outlined"
                    label="Enter Post Title"
                    fullWidth
                    value={formik.values.title}
                    onChange={formik.handleChange}
                    error={formik.touched.title && !!(formik.errors.title)}
                    helperText={formik.touched.title && formik.errors.title}
                />
                <Typography
                    variant="h6"
                    className={classes.postLabel}
                >
                    Post
                </Typography>
                <TextField 
                    className={classes.postDescription}
                    name="description"
                    variant="outlined"
                    label="Enter Post Description"
                    fullWidth
                    multiline
                    rows={20}
                    value={formik.values.description}
                    onChange={formik.handleChange}
                    error={formik.touched.description && !!(formik.errors.description)}
                    helperText={formik.touched.description && formik.errors.description}
                />
                <Button
                    className={classes.buttonSubmit}
                    variant="contained"
                    color="primary"
                    type="submit"
                    size="large"
                    fullWidth                    
                >
                    Publish
                </Button>
            </form>
        </Container>
    )
}

export default Compose;

Cualquier ayuda sería apreciada, gracias.

Edición: Olvidé agregar algunos registros para mostrar. registros al crear una nueva publicación

Edición # 2: Se agregó una consola.log para mostrar la propiedad State.posts.posts después de la llamada CreatePost (). Parece ser una matriz vacía ...

Console.log Resultados después de CreatePost ()

0
vincentyeung 8 jun. 2021 a las 21:42

2 respuestas

La mejor respuesta

Dado que sus datos de las publicaciones de búsqueda API devuelven un objeto con las publicaciones clave. Necesitas cambiar tu envío como

dispatch({
                type: FETCH_POSTS_SUCCESS,
                payload: data.posts
            });

Estabas obteniendo el error antes porque estabas tratando de hacer [... State.posts] donde tus publicaciones eran objeto en lugar de una matriz.

0
Shyam 8 jun. 2021 a las 19:28

Este problema es mayormente causado por un objeto inmutable. En la infraestructura que está utilizando, debe verificar si los estados son inmutables o mutables. Le recomiendo que revise los enlaces que dejé a continuación.

https://imminable-js.github.io/immutable-js/

https://redux.js.org/faq/immutable-data

0
Safa 8 jun. 2021 a las 19:12