Problem using multiple Reducers and Actions Redux - javascript

I have a little problem.
I have diferent reducers in different files using a combine reducer, but when i try to use the "different"
INITIAL STATES on these reducers it doesnt apear
For example
Product Reducer -> This is the state that i have to take
const INITIAL_STATE = {
productosInventario: [],
loading: false,
error: ''
Category Reducer -> this is the state for these reducer
const INITIAL_STATE = {
categorias: [],
categoriaActual: '',
loading: false,
error: ''
}
The idea is use both on these component:
Component:
import React, { Component } from 'react'
/* Components */
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import CardItemInventario from '../components/inventario/CardItemInventario'
import * as ProductoActions from '../actions/ProductoActions'
import * as CategoriasActions from '../actions/CategoriasActions'
/* Styles */
import Spinner from '../components/Spinner'
import Fatal from '../components/Fatal'
import '../assets/styles/Containers/Inventario.scss'
class Inventario extends Component {
async componentDidMount() {
await this.props.traerTodosLosProductos();
}
handleChangeCategoria = (e) => {
this.props.cambioCategoriaInventario(e.target.value)
this.props.traerProductosPorCategoriaInventario(e.target.value)
}
/* Mapea todas las categorias disponibles en base de datos */
traerCategoriasInventario = () => this.props.categoriasInventario.map(category => {
let categori = category.categoria
return (
<option
value={categori}
>
{categori}
</option>
)
})
ponerContenido = () => {
if (this.props.loading) {
return (
<Spinner />
)
}
if (this.props.error) {
return (
<Fatal
error={this.props.error} />
)
}
return (
<>
<div className="button-add__cont">
<h1 className="button-add__title">
Inventario
</h1>
<Link to='/agregarinventario' className="button-add__cont--link">
Agregar a Inventario
</Link>
</div>
<select
name="categoriaSelect"
id=""
onChange={this.handleChangeCategoria}
className="selector-categoria"
>
<option value='' defaultValue> - Categoria -</option>
{this.traerCategoriasInventario()}
</select>
<div className="inventario-cont">
{this.imprimirProductos()}
</div>
</>
)
}
imprimirProductos = () => this.props.productosInventario.map(Productos =>
<CardItemInventario
nombre={Productos.nombre}
marca={Productos.marca}
cantidad={Productos.cantidad}
distribuidor={Productos.distribuidor}
precio={Productos.precio}
/>
)
render() {
console.log(this.props)
return (
<>
{this.ponerContenido()}
</>
)
}
}
const mapStateToProps = (reducers) => {
return (
reducers.ProductoReducer,
reducers.CategoriasReducer
)
}
const mapDispatchToProps = {
...ProductoActions,
...CategoriasActions
}
export default connect(mapStateToProps, mapDispatchToProps)(Inventario);
actions ->
productoActions:
import axios from 'axios'
import {
TRAER_TODOS_LOS_PRODUCTOS
} from '../types/ProductoTypes'
import { host_name, port_redux } from '../../../config'
import { CARGANDO, ERROR } from '../types/GlobalTypes'
const axiosConf = {
baseURL: `http://${host_name}:${port_redux}`
}
export const traerTodosLosProductos = () => async (dispatch) => {
dispatch({
type: CARGANDO
})
try {
const res = await axios.get(`/api/productos/get/listar`, axiosConf)
dispatch({
type: TRAER_TODOS_LOS_PRODUCTOS,
payload: res.data
})
} catch (error) {
console.log("Error: " + error)
dispatch({
type: ERROR,
payload: error.message
})
}
}
export const traerProductosPorCategoriaInventario = (categoria) => async (dispatch) => {
try {
const res = await axios.get(`/api/cotizacion/get/productosporcategoria/${categoria}`, axiosConf)
dispatch({
type: TRAER_TODOS_LOS_PRODUCTOS,
payload: res.data
})
} catch (error) {
console.log("Error: " + error)
dispatch({
type: ERROR,
payload: error.message
})
}
}
categoryActions_ >
import axios from 'axios'
import { host_name, port_redux } from '../../../config'
import { CARGANDO, ERROR } from '../types/GlobalTypes'
import {
LISTAR_CATEGORIAS,
CATEGORIA_ACTUAL
} from '../types/CategoriasTypes'
const axiosConf = {
baseURL: `http://${host_name}:${port_redux}`
}
export const traerCategoriasInventario = () => (dispatch) => {
const res = axios.get(`/api/categorias/get/listar`, axiosConf)
console.log(res)
dispatch({
type: LISTAR_CATEGORIAS,
payload: res.data.data
})
}
export const cambioCategoriaInventario = (categoria) => async (dispatch) => {
try {
dispatch({
type: CATEGORIA_ACTUAL,
payload: categoria
})
} catch (error) {
console.log("Error: " + error)
dispatch({
type: ERROR,
payload: error.message
})
}
}

const mapStateToProps = (reducers) => {
return (
reducers.ProductoReducer,
reducers.CategoriasReducer
)
}
It seems like you are having some confusion between state and reducer. The state is the object which contains all of your data. It is just a plain javascript object. The reducer is a function which takes the state object and an action and returns a new state object.
Your setup should look something like this:
const productoReducer = (state = INITIAL_PRODUCTOS, action ) => {
switch ( action.type ) {
case 'TRAER_TODOS_LOS_PRODUCTOS':
/* ... code here ... */
default:
return state;
}
}
const categoriasReducer = (state = INITIAL_CATEGORIAS, action ) => {
switch ( action.type ) {
case 'LISTAR_CATEGORIAS':
/* ... code here ... */
default:
return state;
}
}
export const reducer = combineReducers({
producto: productoReducer,
categorias: categoriasReducer,
})
Here we have two separate reducers for categories and for products, and each gets a separate initial state. We use combineReducers to put them together so now the combined state has properties producto and categorias.
Your component Inventario needs to access a bunch of values from state: categoriasInventario, productosInventario, loading, and error. Rather than passing the state into the component, we use mapStateToProps to extract these values and pass them as props.
const mapStateToProps = (state) => {
return {
categoriasInventario: state.categorias.categorias,
productosInventario: state.productos.productosInventario,
loading: state.categorias.loading || state.productos.loading,
error: state.categorias.error || state.productos.error,
}
}

Related

Troubles Searching term with Redux Api Rest

I'm having problems filtering info consummed by an api. it is actually the nasa api.
What I Want
Look photos by
Rover's Name (input)
by camera name (input)
by date
I successfully completed the last task but the first input is not bringing the image if I look by the rovers name
Search filter
import React, { useState } from "react";
import { useDispatch } from "react-redux";
import { getPhotos } from "../../redux/actions/getPhotos";
import { ErrorAlert } from "./Alerts";
import './SecondFinder.css';
export default function SecondFinder() {
const dispatch = useDispatch();
const [term, setSearchTerm] = useState("");
const [alertERR, setAlertERR] = useState(false);
const submitHandler = (e) => {
e.preventDefault();
dispatch(getPhotos(term));
}
return (
<form onSubmit={submitHandler}>
<div className="searchPhotosByRover">
<label>Search by Rovers Name</label>
<input type="text" placeholder="Search by Rover" value={term} onChange={(e) => setSearchTerm(e.target.value)} />
<button className="btn-primary">Search</button>
{alertERR ? <ErrorAlert /> : ""}
</div>
</form>
)
}
Component:
import React from "react";
import { useSelector } from "react-redux";
import { LoadingAlert, PhotoNotFoundAlert } from "./Alerts";
import Photos from "./Photos";
export default function GridPhotos() {
const state = useSelector((state) => state.result);
const renderPhotos = () => {
if (state.loading) {
return <LoadingAlert />;
} if (state.photos.length === 0) {
return <PhotoNotFoundAlert />;
}
return state.photos.map((photo, index) => {
return <Photos key={index} photo={photo} index={index} />;
});
};
return <div className="gridPhotos">{renderPhotos()}</div>;
}
Actions:
import axios from "axios";
export const getPhotos = (date, term) => async (dispatch, getState) => {
dispatch({
type: "FETCH_PHOTOS_REQUEST"
})
try {
const response = await axios.get(`https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?earth_date=${date}&name=${term}&api_key=${process.env.REACT_APP_API_KEY}&page=1`)
dispatch({
type: "FETCH_PHOTOS_SUCCESS",
payload: response.data.photos
})
} catch (error) {
dispatch({
type: "FETCH_PHOTOS_FAILURE",
error
})
}
}
Reducer
const initialState = {
photos: [],
loading: false,
error: null
}
export const getPhotosReducer = (state = initialState, action) => {
console.log("action", action)
switch (action.type) {
case "FETCH_PHOTOS_REQUEST":
return {
...state,
loading: true,
error: null
}
case "FETCH_PHOTOS_SUCCESS":
return {
...state,
loading: false,
photos: action.payload
}
case "FETCH_PHOTOS_FAILURE":
return {
...state,
loading: false,
error: action.error,
photos: []
}
default:
return state
}
}
I just want to look by the rovers name and bring a picture based on this name
enter image description here

Uncaught TypeError: Cannot read properties of undefined (reading 'orderItems') and Return Not being created

I'm pretty new to javascript and react, and I'm trying to create a page to return orders for an e-commerce website that I'm creating. I am trying to create this page in a similar way to which the orders are created. Also, I am trying to be able to create a return by pressing a make return button on a customers order history page. My issue is that the order returns are not being created, and currently, in my console in my order history page I'm getting a Uncaught TypeError: Cannot read properties of undefined (reading 'orderItems') error within the const placeDevolucionHandler = () => {dispatch(createDevolucion({ ...order, devolucionItems: order.orderItems })); }; line of my code. I'm unsure why I am having this problem as I followed all the steps that I had done when creating my orders from my cart. I would really appreciate any help or guidance on how to fix this issue.
Thank you!
Note: devolucion is the name that I used in place of return.
OrderHistoryScreen.js
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { listOrderMine, detailsOrder } from '../actions/orderActions';
import LoadingBox from '../components/LoadingBox';
import MessageBox from '../components/MessageBox';
import {createDevolucion } from '../actions/devolucionActions';
import { DEVOLUCION_CREATE_RESET } from '../constants/devolucionConstants';
export default function OrderHistoryScreen(props) {
const orderId = props.match.params.id;
const order = useSelector((state) => state.order);
const devolucionCreate = useSelector((state) => state.devolucionCreate);
const {success, devolucion } = devolucionCreate;
const orderMineList = useSelector((state) => state.orderMineList);
const { loading, error, orders } = orderMineList;
const dispatch = useDispatch();
useEffect(() => {
dispatch(listOrderMine());
dispatch(detailsOrder(orderId));
}, [dispatch, orderId]);
const placeDevolucionHandler = () => {
dispatch(createDevolucion({ ...order, devolucionItems: order.orderItems }));
};
useEffect(() => {
if (success) {
props.history.push(`/devolucion/${devolucion._id}`);
dispatch({ type: DEVOLUCION_CREATE_RESET });
}
}, [dispatch, devolucion, props.history, success]);
return (
<div>
<h1>Order History</h1>
{loading ? (
<LoadingBox></LoadingBox>
) : error ? (
<MessageBox variant="danger">{error}</MessageBox>
) : (
<table className="table">
<thead>
<tr>
<th>ACTIONS</th>
</tr>
</thead>
<tbody>
{orders.map((order) => (
<tr key={order._id}>
<td>
<button
type="button"
onClick={placeDevolucionHandler}
className="small"
>
Make a Return
</button>
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
);
}
PlaceOrderScreen.js
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import {createOrder, } from '../actions/orderActions';
import CheckoutSteps from '../components/CheckoutSteps';
import { ORDER_CREATE_RESET } from '../constants/orderConstants';
import LoadingBox from '../components/LoadingBox';
import MessageBox from '../components/MessageBox';
export default function PlaceOrderScreen(props) {
const cart = useSelector((state) => state.cart);
if (!cart.paymentMethod) {
props.history.push('/payment');
}
const orderCreate = useSelector((state) => state.orderCreate);
const { loading, success, error, order } = orderCreate;
const dispatch = useDispatch();
const placeOrderHandler = () => {
dispatch(createOrder({ ...cart, orderItems: cart.cartItems }));
};
useEffect(() => {
if (success) {
props.history.push(`/order/${order._id}`);
dispatch({ type: ORDER_CREATE_RESET });
}
}, [dispatch, order, props.history, success]);
return (
<div>
<div className="row top">
<div className="col-2">
<div className="card card-body">
<ul>
<li>
<h2>Order Summary</h2>
</li>
<li>
<button
type="button"
onClick={placeOrderHandler}
className="primary block"
disabled={cart.cartItems.length === 0}
>
Place Order
</button>
</li>
{loading && <LoadingBox></LoadingBox>}
{error && <MessageBox variant="danger">{error}</MessageBox>}
</ul>
</div>
</div>
</div>
</div>
);
}
devolucionActions.js
import Axios from 'axios';
import {
DEVOLUCION_CREATE_FAIL,
DEVOLUCION_CREATE_REQUEST,
DEVOLUCION_CREATE_SUCCESS,
DEVOLUCION_DETAILS_FAIL,
DEVOLUCION_DETAILS_REQUEST,
DEVOLUCION_DETAILS_SUCCESS,
DEVOLUCION_PAY_REQUEST,
DEVOLUCION_PAY_FAIL,
DEVOLUCION_PAY_SUCCESS,
DEVOLUCION_MINE_LIST_REQUEST,
DEVOLUCION_MINE_LIST_FAIL,
DEVOLUCION_MINE_LIST_SUCCESS,
DEVOLUCION_LIST_REQUEST,
DEVOLUCION_LIST_SUCCESS,
DEVOLUCION_LIST_FAIL,
DEVOLUCION_DELETE_REQUEST,
DEVOLUCION_DELETE_SUCCESS,
DEVOLUCION_DELETE_FAIL,
DEVOLUCION_SHIPPED_REQUEST,
DEVOLUCION_SHIPPED_SUCCESS,
DEVOLUCION_SHIPPED_FAIL,
DEVOLUCION_DELIVER_REQUEST,
DEVOLUCION_DELIVER_SUCCESS,
DEVOLUCION_DELIVER_FAIL,
DEVOLUCION_SUMMARY_REQUEST,
DEVOLUCION_SUMMARY_SUCCESS,
} from '../constants/devolucionConstants';
export const createDevolucion = (devolucion) => async (dispatch, getState) => {
dispatch({ type: DEVOLUCION_CREATE_REQUEST, payload: devolucion });
try {
const {
userSignin: { userInfo },
} = getState();
const { data } = await Axios.post('/api/devolucions', devolucion, {
headers: {
Authorization: `Bearer ${userInfo.token}`,
},
});
dispatch({ type: DEVOLUCION_CREATE_SUCCESS, payload: data.devolucion });
} catch (error) {
dispatch({
type: DEVOLUCION_CREATE_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message,
});
}
};
export const detailsDevolucion = (devolucionId) => async (dispatch, getState) => {
dispatch({ type: DEVOLUCION_DETAILS_REQUEST, payload: devolucionId });
const {
userSignin: { userInfo },
} = getState();
try {
const { data } = await Axios.get(`/api/devolucions/${devolucionId}`, {
headers: { Authorization: `Bearer ${userInfo.token}` },
});
dispatch({ type: DEVOLUCION_DETAILS_SUCCESS, payload: data });
} catch (error) {
const message =
error.response && error.response.data.message
? error.response.data.message
: error.message;
dispatch({ type: DEVOLUCION_DETAILS_FAIL, payload: message });
}
};
export const listDevolucion = ({ seller = '' }) => async (dispatch, getState) => {
dispatch({ type: DEVOLUCION_LIST_REQUEST });
const {
userSignin: { userInfo },
} = getState();
try {
const { data } = await Axios.get(`/api/devolucions?seller=${seller}`, {
headers: { Authorization: `Bearer ${userInfo.token}` },
});
console.log(data);
dispatch({ type: DEVOLUCION_LIST_SUCCESS, payload: data });
} catch (error) {
const message =
error.response && error.response.data.message
? error.response.data.message
: error.message;
dispatch({ type: DEVOLUCION_LIST_FAIL, payload: message });
}
};
export const summaryDevolucion = () => async (dispatch, getState) => {
dispatch({ type: DEVOLUCION_SUMMARY_REQUEST });
const {
userSignin: { userInfo },
} = getState();
try {
const { data } = await Axios.get('/api/devolucions/summary', {
headers: { Authorization: `Bearer ${userInfo.token}` },
});
dispatch({ type: DEVOLUCION_SUMMARY_SUCCESS, payload: data });
} catch (error) {
dispatch({
type: DEVOLUCION_CREATE_FAIL,
payload:
error.response && error.response.data.message
? error.response.data.message
: error.message,
});
}
};
store.js
import { createStore, compose, applyMiddleware, combineReducers } from 'redux';
import thunk from 'redux-thunk';
import { cartReducer } from './reducers/cartReducers';
import {
devolucionCreateReducer,
devolucionDeleteReducer,
devolucionShipReducer,
devolucionDeliverReducer,
devolucionDetailsReducer,
devolucionListReducer,
devolucionMineListReducer,
devolucionPayReducer,
devolucionSummaryReducer,
} from './reducers/devolucionReducers';
import {
orderCreateReducer,
orderDeleteReducer,
orderShipReducer,
orderDeliverReducer,
orderDetailsReducer,
orderListReducer,
orderMineListReducer,
orderPayReducer,
orderSummaryReducer,
} from './reducers/orderReducers';
import {
productCategoryListReducer,
productCreateReducer,
productDeleteReducer,
productDetailsReducer,
productListReducer,
productReviewCreateReducer,
productUpdateReducer,
} from './reducers/productReducers';
import {
userDeleteReducer,
userDetailsReducer,
userListReducer,
userRegisterReducer,
userSigninReducer,
userUpdateProfileReducer,
userUpdateReducer,
} from './reducers/userReducers';
const initialState = {
userSignin: {
userInfo: localStorage.getItem('userInfo')
? JSON.parse(localStorage.getItem('userInfo'))
: null,
},
cart: {
cartItems: localStorage.getItem('cartItems')
? JSON.parse(localStorage.getItem('cartItems'))
: [],
shippingAddress: localStorage.getItem('shippingAddress')
? JSON.parse(localStorage.getItem('shippingAddress'))
: {},
paymentMethod: 'PayPal',
},
};
const reducer = combineReducers({
productList: productListReducer,
productDetails: productDetailsReducer,
productCreate: productCreateReducer,
productUpdate: productUpdateReducer,
productDelete: productDeleteReducer,
productReviewCreate: productReviewCreateReducer,
productCategoryList: productCategoryListReducer,
cart: cartReducer,
userSignin: userSigninReducer,
userRegister: userRegisterReducer,
userList: userListReducer,
userDelete: userDeleteReducer,
userDetails: userDetailsReducer,
userUpdateProfile: userUpdateProfileReducer,
userUpdate: userUpdateReducer,
orderCreate: orderCreateReducer,
orderDetails: orderDetailsReducer,
orderPay: orderPayReducer,
orderMineList: orderMineListReducer,
orderList: orderListReducer,
orderDelete: orderDeleteReducer,
orderShip: orderShipReducer,
orderDeliver: orderDeliverReducer,
devolucionCreate: devolucionCreateReducer,
devolucionDetails: devolucionDetailsReducer,
devolucionPay: devolucionPayReducer,
devolucionMineList: orderMineListReducer,
devolucionSummary: devolucionSummaryReducer,
devolucionList: devolucionListReducer,
devolucionDelete: devolucionDeleteReducer,
devolucionShip: devolucionShipReducer,
devolucionDeliver: devolucionDeliverReducer,
devolucionSummary: devolucionSummaryReducer,
});
const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducer,
initialState,
composeEnhancer(applyMiddleware(thunk))
);
export default store;

useSelector does not rerender the component when state changes

I'm working on a news aggregator, and I have a Newsfeed component that maps through the relevant posts and creates a Post component for each one. There's a Sidebar component that shows the user the feeds they are subscribed to, and allows them to subscribe to new ones or unsubscribe from existing ones. What I'd like to happen is:
When a user adds a new feed, Newsfeed rerenders and now shows posts from the new feed.
When a user removes a feed, Newsfeed rerender and no longer shows posts from that particular feed.
As far as retrieving the correct posts - my backend takes care of that, and it works fine. The backend returns posts based on the feeds that the user is subscribed to. The problem is, when the user adds or removes a feed, the Newsfeed component does not rerender, and requires a page reload to show the updated feed. At the same time however, the Redux store IS updated, and I can see the state change every time via the Redux Dev Tools.
In Newsfeed, I'm using the useSelector hook to get a few different pieces of state, yet the component does not rerender when the state changes. I was under the impression that any component that used the useSelector hook would automatically be rerendered when that piece of state changed, but if that's not how the hook works then please correct me.
Newsfeed.tsx:
import React, { useState, useRef, useCallback } from "react";
import usePostFetch from "../hooks/usePostFetch";
import { Post } from "./Post";
import { Tag } from "./Tag";
import { Upvote } from "./Upvote";
import { getDate } from "../services/getDate";
import { useSelector } from "react-redux";
import { InitialState } from "../store/reducers/rootReducer";
export const Newsfeed = (props: any) => {
const userState = useSelector((state: InitialState) => {
return state.auth;
});
const { user } = userState;
const publisherState = useSelector((state: InitialState) => {
return state.publishers.publishers;
});
const [pageNumber, setPageNumber] = useState(1);
const { loading, error, posts, hasMore } = usePostFetch(pageNumber);
const observer: any = useRef();
const lastPostElementRef = useCallback(
(node) => {
if (loading) return;
if (observer && observer.current) observer.current.disconnect();
observer.current = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting && hasMore) {
console.log("Visible ");
setPageNumber((prevPageNumber) => prevPageNumber + 1);
}
});
if (node) observer.current.observe(node);
console.log(node);
},
[loading, hasMore]
);
return (
<div className="container mx-auto bg-gray-900" id="newsfeed">
<div className="object-center grid grid-cols-1 gap-8 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5 mx-auto pb-6 pt-6">
{posts.map((post, index) => {
return (
<Post
key={post.id}
title={post.title}
url={post.url}
image={post.image}
category={post.category}
postId={post._id}
created={post.created}
publisher={post.publisher}
upvotes={post.upvotes}
/>
);
})}
</div>
<div>{loading && "Loading..."}</div>
<div>{error && "Error"}</div>
</div>
);
};
publisherActions.ts: (Relevant parts)
export const removeFeed = (allFeeds: any, feedName: any, userId: any) => async (
dispatch: Dispatch<PublisherDispatchTypes>
) => {
try {
axios({
method: "PUT",
url: "users/removepublisher",
params: { publisher: feedName, userId },
})
.then((res) => {
let newAllFeeds = allFeeds.filter((feed: any) => {
return feed.name.localeCompare(feedName) !== 0;
});
allFeeds = newAllFeeds;
console.log(`Feed was removed, ${res}`);
dispatch({
type: REMOVE_FEED_SUCCESS,
payload: allFeeds,
});
})
.catch((err) => {
console.log(`Error removing feed, ${err}`);
dispatch({
type: REMOVE_FEED_FAILURE,
});
});
} catch {
dispatch({ type: REMOVE_FEED_FAILURE });
console.log("Caught error while removing feed");
}
};
export const addFeed = (allFeeds: any, feed: any, userId: any) => async (
dispatch: Dispatch<PublisherDispatchTypes>
) => {
console.log("IN THE ADD_FEED FUNCTION");
try {
axios({
method: "PUT",
url: "users/addpublisher",
params: { publisher: feed, userId },
})
.then((res) => {
console.log(`Feed was added, ${res}`);
dispatch({
type: ADD_FEED_SUCCESS,
payload: {
name: feed.name,
url: feed.url,
image: feed.image,
},
});
})
.catch((err) => {
console.log(`Error adding feed, ${err}`);
dispatch({
type: ADD_FEED_FAILURE,
});
});
} catch {
dispatch({ type: ADD_FEED_FAILURE });
console.log("Caught error while adding feed");
}
publisherReducer.ts: (Relevant parts)
import { Reducer } from "react";
import {
PublisherDispatchTypes,
REMOVE_FEED_SUCCESS,
REMOVE_FEED_FAILURE,
ADD_FEED_SUCCESS,
ADD_FEED_FAILURE,
} from "../actions/publisherActionsTypes";
import { Publisher } from "../../../../shared/Publisher";
interface PublisherResponse {
publishers: Publisher[];
}
export interface PublisherState {
publishers: Publisher[] | undefined;
loadedUsersFeeds: boolean;
feedCount: number;
}
const defaultState: PublisherState = {
publishers: undefined,
loadedUsersFeeds: false,
feedCount: 0,
};
const publisherReducer = (
state: PublisherState = defaultState,
action: PublisherDispatchTypes
) => {
switch (action.type) {
case REMOVE_FEED_SUCCESS:
return {
...state,
publishers: action.payload,
};
case REMOVE_FEED_FAILURE:
return state;
case ADD_FEED_SUCCESS:
let pubs = state.publishers || [];
return {
...state,
publishers: [...pubs, action.payload],
};
case ADD_FEED_FAILURE:
return state;
default:
return state;
}
};
export default publisherReducer;

Redux doesn't update state

I have a problem with Redux doesn't update the state. Component gets right initial state. Action is dispatched right, data is fetched right and is accesible in action payload inside reducer. Reducer is executing, right case in switch is picked. Just new state doesn't appear in component. I have three others components where it works just fine, only this one cracks.
component
import fetchLinksPage from '../state/links/actions'
...
let Links = ({linksPageLoaded, linksPage, fetchLinksPage}) => {
useEffect( () => {
if(!linksPageLoaded) {
fetchLinksPage()
console.log(linksPage)
}
},[])
return ( ... )
}
const mapStateToProps = ({linksPageReducer}) => {
return linksPageReducer
}
const mapDispatchToProps = dispatch => {
return {
fetchLinksPage: () => dispatch(fetchLinksPage())
}
}
Links = connect(mapStateToProps, mapDispatchToProps)(Links)
actions
// action types
export const GET_LINKS_PAGE = 'GETLINKSPAGE'
export const LINKS_PAGE_LOADED = 'LINKSPAGELOADED'
export const LINKS_PAGE_ERROR = 'LINKSPAGEERROR'
// action creators
export const getLinksPage = () => {
return {
type: GET_LINKS_PAGE
}
}
export const linksPageLoaded = (data) => {
return {
type: LINKS_PAGE_LOADED,
payload: data
}
}
export const linksPageError = (error) => {
return {
type: LINKS_PAGE_ERROR,
payload: error
}
}
const fetchLinksPage = () => {
return dispatch => {
dispatch(getLinksPage())
fetch('http://portfolio.adamzajac.info/_/items/links?fields=*,logo.*.*')
.then(response => response.json())
.then(data => {
dispatch(linksPageLoaded(data.data))
})
.catch( error => {
dispatch(linksPageError(error))
})
}
}
export default fetchLinksPage
reducer
import * as actions from './actions.js'
const linksPageReducer = (state={}, action) => {
switch (action.type) {
case actions.GET_LINKS_PAGE:
return { ...state, linksPageLoading: true }
case actions.LINKS_PAGE_LOADED:
//console.log('update state')
return { ...state, linksPage: action.payload, linksPageLoading: false, linksPageLoaded: true }
case actions.LINKS_PAGE_ERROR:
return { ...state, linksPageError: action.payload, linksPageLoading: false}
default:
return { ...state, linksPageLoading: false, linksPageLoaded: false, linksPage:[], linksPageError:''}
}
}
export default linksPageReducer
store
import aboutPageReducer from './state/about/reducer'
import projectsPageReducer from './state/projects/reducer'
import skillsPageReducer from './state/skills/reducer'
import linksPageReducer from './state/links/reducer'
const rootReducer = combineReducers({
aboutPageReducer,
projectsPageReducer,
skillsPageReducer,
linksPageReducer
})
const store = createStore(
rootReducer,
applyMiddleware(thunk)
)

React Native Firebase Fetching Only One Data

How can I fetch only one data and write it to Header ?
I am using firebase and react-redux.
firebase structure i try to write "organization": inovanka:
Action File Codes:
import firebase from 'firebase';
import { Actions } from 'react-native-router-flux';
import { ORGANIZATION_NAME_DATA_SUCCESS } from './types';
export const organizationName = () => {
const { currentUser } = firebase.auth();
return (dispatch) => {
firebase.database().ref(`/organizations/${currentUser.uid}`)
.on('value', snapshot => {
dispatch({ type: ORGANIZATION_NAME_DATA_SUCCESS, payload: snapshot.val() });
});
};
}
Reducer File :
import { ORGANIZATION_NAME_DATA_SUCCESS } from '../actions/types';
const INITIAL_STATE = {
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case ORGANIZATION_NAME_DATA_SUCCESS:
console.log(action); // data retrieved as array
return action.payload
default:
return state;
}
};
Component: (I would like to write it to this)
class HomePage extends Component {
componentWillMount() {
}
render() {
return (
<Container>
<Header>
<Text> i would like to write it here </Text>
</Header>
<Content>
</Content>
</Container>
);
}
}
const mapStateToProps = ({ homepageResponse }) => {
const organizationArray = _.map(homepageResponse, (val, uid) => {
return { ...val, uid }; //
});
return { organizationArray };
};
export default connect(mapStateToProps, { organizationName })(HomePage);
Change this:
firebase.database().ref(`/organizations/${currentUser.uid}`)
.on('value', snapshot => {
to this:
firebase.database().ref(`/organizations/${currentUser.uid}`)
.once('value', snapshot => {
using once() will read data only one time, thus fetching only one data
Solution is Here !
Action File:
export const organizationName = () => {
const { currentUser } = firebase.auth();
return (dispatch) => {
firebase.database().ref(`/organizations/${currentUser.uid}`)
.once('value', snapshot => {
_.mapValues(snapshot.val(), o => {
console.log(o);
dispatch({ type: ORGANIZATION_NAME_DATA_SUCCESS, payload: {organization: o.organization, fullname: o.fullname }});
});
});
};
}
Reducer File
const INITIAL_STATE = {
organization: '',
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case ORGANIZATION_NAME_DATA_SUCCESS:
console.log(action);
return {...state, organization:action.payload.organization };
default:
return state;
}
};
Component File MapToStateProps and componentWillMount
const mapStateToProps = state => {
const { organization, fullname } = state.homepageResponse;
console.log("burada" + organization);
return { organization, fullname };
};
componentWillMount(){
this.props.organizationName();
}
*Last Step Header *
render() {
return (
<Container>
<Header>
<Text> { this.props.organization } </Text>
</Header>
</Container>
}
Thank You Everyone

Categories