K
K
km170682tvv2020-10-05 22:22:12
React
km170682tvv, 2020-10-05 22:22:12

Why is state updated globally in React/Redux but not updated in components?

When loading the parent component, I make a request to the backend (Laravel) to check if the user is authorized and get his data. After receiving a response, I store this data in the state store using the dispatch function. But in the components (neither in the children nor in the update itself. I check this.props.state in any method of the component and everywhere I get only the initial state, without the received data. At the same time, the data has been updated globally, I see them in the console using subscriptions (store.subsrube())
What am I doing wrong

store.js

import { createStore } from 'redux';

const store = createStore(reducer);

function reducer(state = {is_auth : false}, action) {
  if (action.type === 'GET_AUTH') {
    state.auth = action.payload;
    state.is_auth = true;
  }
  return state;
}

export default store;

store.subscribe(() => console.info(store.getState()))


app.js
import React, { Component }  from 'react';
import { connect } from 'react-redux';
import Main from './Main';
import Navigation from './Navigation';


class App extends Component {

  authRequest() {
    console.log('auth: ' + Date.now())
    if (this.checkToken()) {
      axios.get('/api/current',{
        headers: {'Authorization' : 'Bearer ' + sessionStorage.getItem('token')}
      })
      .then((response) => {
        this.props.onGetAuth(response.data);
      })
      .catch((error) => {
        console.log(error);
      })
    }
  }

  checkToken() {
    return sessionStorage.getItem('token') && Date.parse(sessionStorage.getItem('token_expires')) > Date.now();
  }

  render() {

    if (this.props.is_auth == false) this.authRequest();

    return ( 
      <div>
      <Navigation /> 
      <Main /> 
      </div> 
    );
  }
}

const mapStateToProps = state => {
  return state
}

const mapDispatchToProps = dispatch => {
  return {
    onGetAuth : (auth) => {
      dispatch({ type: 'GET_AUTH', payload: auth })
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(App);

Answer the question

In order to leave comments, you need to log in

2 answer(s)
G
Gimir, 2020-10-06
@km170682tvv

The problem lies here

function reducer(state = {is_auth : false}, action) {
  if (action.type === 'GET_AUTH') {
    state.auth = action.payload;
    state.is_auth = true;
  }
  return state;
}

You are mutating the state, redux will not work like that, you must always return a new state, read the redux documentation. Try it like this:
function reducer(state = {is_auth : false, auth: null}, action) {
  if (action.type === 'GET_AUTH') {
    return {
       auth: action.payload,
       is_auth: true
    }
  }
  return state;
}

And make sure that the default state has all the intended properties.

Z
Zhanna_K, 2020-10-05
@Zhanna_K

I don’t know what exactly the problem is, but from what I saw:
1) asynchronous api requests should be in the ComponentDidMount () method, you have them in the renderer, you shouldn’t do this
2) the reducer should be a "pure function", then there is to create a deep copy of the state, and it is it that has to be changed and returned
PS. I am not an expert on react, I myself am in the process of learning

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question