Action is dispatched, but state is not updating - javascript

I am new to redux, and I have read the other questions concerning this topic. I have tried and looked for quite sometime at this point. I am using redux dev tools in and chrome, and can see my action pulling in the information I need, but it is not going to the state. Here is some of my code, any help would be greatly appreciated.
actions.js
export const FETCH_DATA = {
FETCH_DATA_BEGIN: "FETCH_DATA_BEGIN",
FETCH_DATA_SUCCESS: "FETCH_DATA_SUCCESS",
FETCH_DATA_FAILURE: "FETCH_DATA_FAILURE",
};
export const fetchDataBegin = () => ({
type: FETCH_DATA.FETCH_DATA_BEGIN,
});
export const fetchDataSuccess = (data) => ({
type: FETCH_DATA.FETCH_DATA_SUCCESS,
payload: data,
});
Reducers.js
import { FETCH_DATA } from "./actions";
const initialState = {
data: [],
loading: false,
error: null,
};
export default function displayDataReducer(state = initialState, action) {
switch (action.type) {
case FETCH_DATA.FETCH_DATA_BEGIN:
return {
...state,
loading: true,
error: null,
};
//Sets the data
case FETCH_DATA.FETCH_DATA_SUCCESS:
return {
...state,
loading: false,
data: action.payload.data,
};
my store/index.js
import { createStore, combineReducers, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import displayDataReducer from "./displayData/reducer";
// The Dev Tool extension for the browser
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
// export const RootReducer = combineReducers({
// data: displayDataReducer,
// });
export default createStore(
displayDataReducer,
composeEnhancers(applyMiddleware(thunk))
);
my component
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import axios from "axios";
import Navbar from "../brand/Navbar";
import Masthead from "../brand/Masthead";
import Footer from "../brand/Footer";
import MainContent from "../content/MainContent";
function App() {
const content = useSelector((state) => state);
const dispatch = useDispatch();
function getData() {
return (dispatch) => {
axios.get("https://jsonplaceholder.typicode.com/todos/1").then((res) =>
dispatch({
type: "FETCH_DATA.FETCH_DATA_SUCCESS",
data: res.data,
})
);
};
}
useEffect(() => {
dispatch(getData());
}, []);

Issue: type: "FETCH_DATA.FETCH_DATA_SUCCESS" should just be type: "FETCH_DATA_SUCCESS", or perhaps you didn't mean to include the quotes around it, in which case you also need to import FETCH_DATA.
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import axios from "axios";
import Navbar from "../brand/Navbar";
import Masthead from "../brand/Masthead";
import Footer from "../brand/Footer";
import MainContent from "../content/MainContent";
function App() {
const content = useSelector((state) => state);
const dispatch = useDispatch();
function getData() {
return (dispatch) => {
axios.get("https://jsonplaceholder.typicode.com/todos/1").then((res) =>
dispatch({
type: "FETCH_DATA_SUCCESS", // <-- Drop the prefix
data: res.data,
})
);
};
}
OR
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import axios from "axios";
import { FETCH_DATA } from "./actions"; // <-- import actions
import Navbar from "../brand/Navbar";
import Masthead from "../brand/Masthead";
import Footer from "../brand/Footer";
import MainContent from "../content/MainContent";
function App() {
const content = useSelector((state) => state);
const dispatch = useDispatch();
function getData() {
return (dispatch) => {
axios.get("https://jsonplaceholder.typicode.com/todos/1").then((res) =>
dispatch({
type: FETCH_DATA.FETCH_DATA_SUCCESS,
data: res.data,
})
);
};
}

Related

Redux state not updating in function component

I am working on a signup React app that uses redux. Everything other thing works quite right with the exception of state update.
I've gone through several recommendations already given here and I don't seem to see what's wrong with the code.
The authAction.js
import { API_URL } from '../../../constants/constants';
const LOGIN_SUCCESSFUL = 'LOGIN_SUCCESSFUL';
const LOGIN_LOADING = 'LOGIN_LOADING';
const LOGIN_FAILED = 'LOGIN_FAILED';
const login = values => {
let url = API_URL + 'login';
return async (dispatch) => {
dispatch({
type: LOGIN_LOADING
})
const response = await fetch (url, {
method: 'POST',
body: JSON.stringify(values),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
});
const data = await response.json();
console.log(data);
if(response.status >=200 && response.status <= 299)
{
sessionStorage.setItem('_token', data.data.jwt)
dispatch({
type: LOGIN_SUCCESSFUL,
payload: {
isAuthenticated: true,
jwt: data.data.jwt ?? ''
}
});
}
dispatch({
type: LOGIN_FAILED,
payload: {
isAuthenticated: false,
jwt: '',
message: data?.message ?? 'Authentication failed.'
}
})
}
}
export { login, logout };
authReducer.js
const LOGIN_SUCCESSFUL = 'LOGIN_SUCCESSFUL';
const LOGIN_FAILED = 'LOGIN_FAILED';
const LOGIN_LOADING = 'LOGIN_LOADING';
const initialState = {
jwt: '',
isAuthenticated: false,
message: '',
loading: false,
error: false,
};
const authReducer = (state = initialState, action) => {
if(action.type === LOGIN_LOADING)
{
return {
...state,
message: 'Authenticating...',
loading: true
}
}
if(action.type === LOGIN_SUCCESSFUL)
{
return {
...state,
isAuthenticated: true,
jwt: action.payload.jwt,
message: action.payload.message,
laoding: false,
error: true
}
}
if(action.type === LOGIN_FAILED)
{
return {
...state,
jwt: '',
isAuthenticated: false,
loading: false
};
}
return initialState;
}
export default authReducer;
rootReducer.js where I combined other reducers
import { combineReducers } from "redux";
import userReducer from "./users/userReducer";
import authReducer from './users/authReducer';
import signupReducer from './users/signupReducer';
import postReducer from './postReducer'
const rootReducer = combineReducers({
user: userReducer,
auth: authReducer,
signup: signupReducer,
posts: postReducer
});
export default rootReducer;
signup.js that handles the view
import {useFormik } from 'formik';
import React, { useEffect } from 'react';
import { Helmet } from 'react-helmet';
import { Link, Navigate } from 'react-router-dom';
import { useSelector, useDispatch } from 'react-redux';
import * as Yup from 'yup';
import logo from '../../assets/img/logo1.jpeg';
import Error from '../../components/forms/Error';
import LandingLayout from '../layouts/landing';
import signup from '../../redux/actions/users/signupActions';
import Toast from '../../components/alerts/Toast';
const Signup = () => {
const {loading, error, status} = useSelector(state => state.signup);
const dispatch = useDispatch();
useEffect(()=>{
if(status)
{
setTimeout(() => {
return <Navigate to='/login' />
}, 2000);
}
}, [dispatch, status])
...
onSubmit: (values) => {
dispatch(signup(values));
}
...
export default Signup;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk'
import { composeWithDevTools } from 'redux-devtools-extension'
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import rootReducer from './redux/reducers/rootReducer';
const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)));
ReactDOM.render(
<React.StrictMode>
<Provider store = {store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
when a log the response from the API call, I get the expected response but nothing is effected on the UI.
Well, it appears that the error was coming from somewhere else. Just as previously stated, everything I did was quite right aside the fact that one of the reducers - userReducer - included in the rootReducer had its action creator returning the wrong payload.
I commented that out and everything else worked.
However, should subtle bug from one reducer affect the entire workings of the store?

Redux and Axios get. method not returning any data

Need some help.
As I am trying to get some understanding of React/REdux global state I made some simple get request.
This is done with Axios, thunk, Redux, but i can't get this working
I have Post.js file, nothing fancy
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import PostForm from './PostForm';
export class Post extends Component {
static propTypes = {
posts: PropTypes.any,
fetchPosts: PropTypes.func,
};
componentDidMount() {
const { fetchPosts } = this.props;
fetchPosts();
}
render() {
const { posts } = this.props;
return (
<div>
<PostForm addPost={this.onSubmit} />
<br />
<div>
{posts.map(post => (
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</div>
))}
</div>
</div>
);
}
}
export default Post;
Next i have my PostContainer.js
import { connect } from 'react-redux';
import Post from './Post';
import { fetchFromApi } from '../reducers/postReducers';
const mapStateToProps = state => ({
posts: state.posts,
});
const mapDispatchToProps = dispatch => ({
fetchPosts: () => dispatch(fetchFromApi()),
});
export default connect(mapStateToProps, mapDispatchToProps)(Post);
My reducer
import Axios from 'axios';
/* action type */
const FETCH_POSTS = 'FETCH_POSTS';
/* action creator */
export const fetchStarted = payload => ({ payload, type: FETCH_POSTS });
/* thunk */
export const fetchFromApi = () => {
return (dispatch, getState) => {
Axios.get('https://jsonplaceholder.typicode.com/posts?_limit=5').then(res =>
dispatch(fetchStarted(res.data))
);
};
};
/* reducer */
export default function reducer(state = [], action = {}) {
switch (action.type) {
case FETCH_POSTS: {
return {
...state,
data: action.payload,
};
}
default:
return state;
}
}
and my store
import { combineReducers, applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';
import postReducer from './reducers/postReducers';
const initialState = {
posts: {
data: {},
},
};
const reducers = {
posts: postReducer,
};
Object.keys(initialState).forEach(item => {
if (typeof reducers[item] == 'undefined') {
reducers[item] = (state = null) => state;
}
});
const combinedReducers = combineReducers(reducers);
const store = createStore(
combinedReducers,
initialState,
composeWithDevTools(applyMiddleware(thunk))
);
export default store;
All of that is doing not much. My map method is trying to map empty posts object. And for some reason my fetchPosts is not dispatched. I have reade some old posts here but still can't get this working
Thanks
Edit
this is my app.js file with container
import React from 'react';
import './App.css';
import Post from './components/PostContainer';
import { Provider } from 'react-redux';
import store from './store';
function App() {
return (
<Provider store={store}>
<div className='App'>
<Post />
</div>
</Provider>
);
}
export default App;
I managed to get this working.
Data was not there when my posts array was render. After passing simple if statemante all is working

How to dispatch an action and show the data in the app.js using react/redux

I don't know how to load the data of the fetchLatestAnime action in the react app.js file.
My mission is to show the endpoint data that I am doing fetch.
I have already implemented the part of the reducers and action, which you can see in the part below. The only thing I need is to learn how to display the data.
App.js
import React from 'react';
import './App.css';
function App() {
return (
<div className="App">
</div>
);
}
export default App;
actions/types.js
export const FETCHING_ANIME_REQUEST = 'FETCHING_ANIME_REQUEST';
export const FETCHING_ANIME_SUCCESS = 'FETCHING_ANIME_SUCCESS';
export const FETCHING_ANIME_FAILURE = 'FETCHING_ANIME_FAILURE';
actions/animesActions.js
import{
FETCHING_ANIME_FAILURE,
FETCHING_ANIME_REQUEST,
FETCHING_ANIME_SUCCESS
} from './types';
import axios from 'axios';
export const fetchingAnimeRequest = () => ({
type: FETCHING_ANIME_REQUEST
});
export const fetchingAnimeSuccess = (json) => ({
type: FETCHING_ANIME_SUCCESS,
payload: json
});
export const fetchingAnimeFailure = (error) => ({
type: FETCHING_ANIME_FAILURE,
payload: error
});
export const fetchLatestAnime = () =>{
return async dispatch =>{
dispatch(fetchingAnimeRequest());
try{
let res = await axios.get('https://animeflv.chrismichael.now.sh/api/v1/latestAnimeAdded');
let json = await res.data;
dispatch(fetchingAnimeSuccess(json));
}catch(error){
dispatch(fetchingAnimeFailure(error));
}
};
};
reducers/latestAnimeReducers.js
import {
FETCHING_ANIME_FAILURE,
FETCHING_ANIME_REQUEST,
FETCHING_ANIME_SUCCESS
} from '../actions/types';
const initialState = {
isFetching: false,
errorMessage: '',
latestAnime: []
};
const latestAnimeReducer = (state = initialState , action) =>{
switch (action.type){
case FETCHING_ANIME_REQUEST:
return{
...state,
isFetching: true,
}
case FETCHING_ANIME_FAILURE:
return{
...state,
isFetching: false,
errorMessage: action.payload
}
case FETCHING_ANIME_SUCCESS:
return{
...state,
isFetching: false,
latestAnime: action.payload
}
default:
return state;
}
};
export default latestAnimeReducer;
reducers/index.js
import latestAnimeReducers from './latestAnimeReducers'
import {combineReducers} from 'redux';
const reducers = combineReducers({
latestAnimeReducers
});
export default reducers;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import resolvers from './redux/reducers/index';
import {createStore , applyMiddleware} from 'redux';
import {Provider} from 'react-redux';
import thunk from 'redux-thunk';
const REDUX_DEV_TOOLS = window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const store = createStoreWithMiddleware(resolvers , REDUX_DEV_TOOLS)
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
serviceWorker.unregister();
Ideally, this is how your app.js should look like. I created a working codesandbox for you here. Your initial latestAnime state was an empty array but the action payload you set to it is an object, so remember to pass payload.anime like i have done in the sandbox.
import React, { useEffect } from "react";
import { connect } from "react-redux";
import { fetchLatestAnime } from "./redux/actions/animesActions";
const App = props => {
const { fetchLatestAnime, isFetching, latestAnime, errorMessage } = props;
useEffect(() => {
fetchLatestAnime();
}, [fetchLatestAnime]);
console.log(props);
if (isFetching) {
return <p>Loading</p>;
}
if (!isFetching && latestAnime.length === 0) {
return <p>No animes to show</p>;
}
if (!isFetching && errorMessage.length > 0) {
return <p>{errorMessage}</p>;
}
return (
<div>
{latestAnime.map((anime, index) => {
return <p key={index}>{anime.title}</p>;
})}
</div>
);
};
const mapState = state => {
return {
isFetching: state.latestAnimeReducers.isFetching,
latestAnime: state.latestAnimeReducers.latestAnime,
errorMessage: state.latestAnimeReducers.errorMessage
};
};
const mapDispatch = dispatch => {
return {
fetchLatestAnime: () => dispatch(fetchLatestAnime())
};
};
export default connect(
mapState,
mapDispatch
)(App);

React-Redux Action: 'Dispatch' is not a function

Still getting used to Redux, first off. I have a component that should simply load data for display when the component loads. I have redux setup with the store:
//store.js
import { createStore, applyMiddleware, compose } from 'redux';
import logger from 'redux-logger';
import thunk from 'redux-thunk';
import root from './reducers';
const middleware = [thunk, logger];
const initState = {};
const store = createStore(
root,
initState,
compose(
applyMiddleware(...middleware),
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)
);
export default store;
and all the reducers that I'll need in a full on combine reducers file:
//{projectFolder}/reducers/index.js
import { combineReducers } from 'redux';
import authReducer from './authReducer';
import errorsReducer from './errorReducer';
import suggestionReducer from './suggestionReducer';
import insiderReducer from './insiderReducer';
import connectionReducer from './connectionReducer';
import outsiderReducer from './outsiderReducer';
import contactReducer from './contactReducer';
import metaReducer from './metaReducer';
export default combineReducers({
auth: authReducer,
errors: errorsReducer,
suggestions: suggestionReducer,
insider: insiderReducer,
connection: connectionReducer,
outsider: outsiderReducer,
contact: contactReducer,
meta: metaReducer
});
The one that I'm interested in is the metaReducer which is the called by an action, or so it should be.
//metaReducer.js
import {GET_INSIDER_META_INFORMATION, GET_OUTSIDER_META_INFORMATION } from '../actions/types';
const initState = {
insider: {},
outsider: {}
};
export default (state = initState, { type, payload }) => {
switch (type) {
case GET_INSIDER_META_INFORMATION:
return{
...state,
insider: payload
}
case GET_OUTSIDER_META_INFORMATION:
return {
...state,
outsider: payload
}
default:
return state;
}
};
The meta reducer is just to house the information coming from the back-end and is each case of the reducer is called from the actions/meta.js file which looks like this:
//{projectfolder}/actions/meta.js
import {
GET_INSIDER_META_INFORMATION,
GET_OUTSIDER_META_INFORMATION,
POPULATE_ERRORS
} from "./types";
import Axios from "axios";
export const getMetaInsider = (dispatch) => {
return Axios.get("meta/insiders")
.then(res =>
dispatch({ type: GET_INSIDER_META_INFORMATION, payload: res.data })
)
.catch(err =>
dispatch({ type: POPULATE_ERRORS, payload: err.response.data })
);
};
export const getMetaOutsider = (dispatch) => {
return Axios.get("meta/outsiders")
.then(res => {
dispatch({ type: GET_OUTSIDER_META_INFORMATION, payload: res.data });
})
.catch(err =>
dispatch({ type: POPULATE_ERRORS, payload: err.response.data })
);
};
and My component that calls all of this is setup as below:
//{projectfolder}/components/home.js
import React, {Component} from 'react';
import {Card, CardTitle, CardSubtitle, CardBody} from 'reactstrap';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import {getMetaInsider, getMetaOutsider} from '../actions/meta';
class Home extends Component{
constructor(props){
super(props);
this.state = {
insider:{},
outsider: {}
}
}
componentDidMount() {
console.log(this.props);
this.props.getMetaInsider();
this.props.getMetaOutsider();
}
render(){
let {insiders, outsiders} = this.state;
return(
<React.Fragment>
{*/ omitted as it's not really an issue right now, data is more important than layout /*}
</React.Fragment>
)
}
}
const mapState = state => {
console.log(state);
return {
insider: state.meta.insider,
outsider: state.meta.outsider
}
};
Home.propTypes = {
getMetaInsider: PropTypes.func.isRequired,
getMetaOutsider: PropTypes.func.isRequired,
insider: PropTypes.object.isRequired,
outsider: PropTypes.object.isRequired
};
export default connect(mapState, {getMetaInsider, getMetaOutsider})(Home);
So when the component loads, I get a horribly weird issue where it looks like jquery is being called, and it's imported in my App.js file for bootstrap. However, the main error is this:
"TypeError: dispatch is not a function
at http://localhost:3000/static/js/bundle.js:73524:22"
Which maps up to the .catch block of the getMetaInsider function.
You have to do something like this:
export const getMetaOutsider = () => {
return (dispatch) => {
Axios.get("meta/outsiders")
.then(res => {
dispatch({ type: GET_OUTSIDER_META_INFORMATION, payload: res.data });
})
.catch(err =>
dispatch({ type: POPULATE_ERRORS, payload: err.response.data })
);
}
};
Try this, It should work. Feedbacks are welcome.
redux-thunk handles functions passed as the argument to dispatch instead of objects.

Redux firing undefined action while using redux thunk

This issue likely stems from a misconfiguration of redux-thunk or a misunderstanding of how to write a thunk. I've tried a lot of different ways, but from what I can tell, this should work. However, I'm still getting a console message that says its firing a redux action of undefined.
Here is my store configuration
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import App from './components/App';
import rootReducer from './reducers';
const store = createStore(rootReducer, applyMiddleware(thunk));
ReactDOM.render(
<Provider store={ store }>
<App />
</Provider>,
document.getElementById('rootElement')
);
Here is my action:
import axios from 'axios';
export const GET_ABOUT_CONTENT_REQUEST = 'GET_ABOUT_CONTENT_REQUEST';
export const GET_ABOUT_CONTENT_FAILED = 'GET_ABOUT_CONTENT_FAILED';
export const GET_ABOUT_CONTENT_OK = 'GET_ABOUT_CONTENT_OK';
export const fetchAboutContent = () => {
const url = `http://localhost:3000/about`;
return (dispatch, getState) => {
if (getState.isInitialized === true){
console.log("desktop init should not be called when already desktop is init")
return Promise.resolve();
}
if (getState.about.isLoading) {
console.log('is loading');
return Promise.resolve();
}
dispatch({ type: GET_ABOUT_CONTENT_REQUEST });
axios.get(url)
.then(res => dispatch({
type: GET_ABOUT_CONTENT_OK,
res
}))
.error(err => dispatch({
type: GET_ABOUT_CONTENT_FAILED,
err
}));
}
}
Here is me firing the action in my component:
import React from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as actions from '../../actions/about';
import getAboutContent from '../../reducers';
class AboutMe extends React.Component {
constructor(props) {
super(props);
}
componentWillMount() {
this.props.getAboutContent();
}
render() {
return <div>{ this.props.content }</div>
}
}
const mapStateToProps = (state) => ({
content: {} || getAboutContent(state)
})
const mapDispatchToProps = (dispatch) =>
bindActionCreators({ getAboutContent }, dispatch)
export default connect(
mapStateToProps, mapDispatchToProps
)(AboutMe);
I've tried quite a few configurations for mapDispatchToProps, i.e. connect(..., { fetchData: getAboutContent })..., and more. Any help is greatly appreciated.
Edit:
Here is the git repo, if that is helpful to anybody: https://github.com/sambigelow44/portfolio-page
Check your reducer name,you export fetchAboutContent, but import getAboutContent.
Code in action file is seems to be incorrect.
getState is a function.
const state = getState();
Change below code.
import axios from 'axios';
export const GET_ABOUT_CONTENT_REQUEST = 'GET_ABOUT_CONTENT_REQUEST';
export const GET_ABOUT_CONTENT_FAILED = 'GET_ABOUT_CONTENT_FAILED';
export const GET_ABOUT_CONTENT_OK = 'GET_ABOUT_CONTENT_OK';
export const fetchAboutContent = () => {
const url = `http://localhost:3000/about`;
return (dispatch, getState) => {
if (getState().isInitialized === true){
console.log("desktop init should not be called when already desktop is init")
return Promise.resolve();
}
if (getState().about.isLoading) {
console.log('is loading');
return Promise.resolve();
}
dispatch({ type: GET_ABOUT_CONTENT_REQUEST });
axios.get(url)
.then(res => dispatch({
type: GET_ABOUT_CONTENT_OK,
res
}))
.error(err => dispatch({
type: GET_ABOUT_CONTENT_FAILED,
err
}));
}
}
Also you need to return promise from axios call, just add return statement.
return axios.get(url)
.then(res => dispatch({
type: GET_ABOUT_CONTENT_OK,
res
}))
.error(err => dispatch({
type: GET_ABOUT_CONTENT_FAILED,
err
}));

Categories