2
votes

While using react-redux and mapping state to props with connect() the received state has the correct values but when accessing the variables through this.props "this" is always undefined.

When pressing the button (in there for test purposes only) on the sidebar component the second console log always fails with TypeError: Cannot read property 'props' of undefined on console.log(this.props.visibility).

Am i missing something extra that is needed in order to allow access of the newly maped values in mapStateToProps through this.props ? or even if i should be accessing them in another way other then this.props.

Thanks in advance.

The component

import React, { Component } from 'react';
import {connect} from 'react-redux';
import {toggleSidebarVisibility } from '../../actions/layoutActions';


class Sidebar extends Component{

    render(){
      return(
        <div>
          <button class='btn btn-secondary' onClick={test}>B</button>
        </div>      
      );        
    }
}

function test(){
  console.log("hello");
  console.log(this.props.visibility)

}

const mapStateToProps = (state) => {
  console.log(state);
  console.log(state.layout.sidebarVisibility);
  return {
    visibility: state.layout.sidebarVisibility,
  }
};

App.js

import React, { Component } from 'react';
import logo from './logo.svg';
import { Provider } from 'react-redux';
import Sidebar from './components/layout/Sidebar';
import Header from './components/layout/Header';
import store from './store';

class App extends Component {
  render() {
    return (
      <Provider store ={store}>
        <div className="App">
          <Header />
          <Sidebar/>
        </div>
      </Provider>
    );
  }
}

export default App;

Store.js

import { createStore, applyMiddleware,compose} from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

const initialState = {

};

const middleWare = [thunk];

const store = createStore(rootReducer,initialState,compose(
    applyMiddleware(...middleWare),
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
    ));

export default store;

RootReducer

import {combineReducers } from 'redux';
import layoutReducer from './layoutReducer';

export default combineReducers({
    layout : layoutReducer
});

LayoutReduccer

import {TOGGLE_SIDEBAR_VIS} from '../actions/types';

const initialState  = {
    sidebarVisibility : true
}

export default function(state = initialState,action){
    switch(action.type){
        case TOGGLE_SIDEBAR_VIS:
            return{ ...state,sidebarVisibility:action.payload};   
        default:
            return state;
    }
}
2
You need to set the context of the test function, you can do that using something like this: onClick={test.bind(this)}Titus
use an arrow function for testHarold

2 Answers

0
votes

This is related to JavaScript#lexical scoping.

One need to bind to component this using .bind or JavaScript#arrow function.

Sol1 : Using JavaScript#arrow function :

test = () => {
  console.log("hello");
  console.log(this.props.visibility)

}

Sol2: Using explicit this binding using JavaScript#bind.

inside constructor:

constructor(){

  this.test = this.test.bind(this);
}


test(){
  //code
}
0
votes

When you write functions inside class/statefull component they no need function keyword before function name. So test function can be written as test(){ or arrow function test = () => {

The reason this is undefined inside function in your case because function needs binding in order to access this and state or props. Either you need to manually bind the function in constructor or change it to arrow function like I did below

Approach 1:

Manually bind the function in constructor

      constructor(props){
           super(props);
           this.test = this.test.bind(this);
       }

       test = () => {
          console.log("hello");
          console.log(this.props.visibility);
      }

OR

Approach2:

You can change test function to arrow function hence manual binding in constructor isn’t required because arrow functions takes binding automatically thus this is available inside arrow function

Change

function test(){
  console.log("hello");
  console.log(this.props.visibility);
}

To

test = () => {
  console.log("hello");
  console.log(this.props.visibility);
}