chobo2
chobo2

Reputation: 85865

How to hookup input boxes to Reactjs / Redux?

I not 100% sure if I am doing this right as per the redux design.

import React from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import 'materialize-css/sass/materialize.scss';
import NavigationContainer from './NavigationContainer';

import AddStorageModal from './AddStorageModal.js'
import {loadAddStorageModal, createNewStorage} from '../actions/StorageActions.js'
import '../styles/main.scss';


class App extends React.Component {
  render() {
    return (
      <div>
        <NavigationContainer />
        <AddStorageModal {...this.props} />
      </div>
    )
  }
}

function mapStateToProps(state) {
    return {
        storages: state.storages
    };
}

function matchDispatchToProps(dispatch){
    return bindActionCreators({loadAddStorageModal: loadAddStorageModal, createNewStorage: createNewStorage}, dispatch);
}


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

StorageActions

export function fetchStorage() {
  return function(dispatch) {
      var payload = [
        {
            id: 1,
            name: "Fridge2"
        },
        {
            id: 2,
            name: "Closet2"
        },
        {
            id: 3,
            name: "Car2"
        }
    ];
     dispatch({type: "Fetch_Storage", payload: payload});
  }
}

export function loadAddStorageModal(load) {
    return function(dispatch) {
         dispatch({type: "Load_Add_Storage_Modal", payload: load});
    }
}

export function createNewStorage(storage) {
    return function(dispatch) {
         dispatch({type: "New_Storage_Created", payload: storage});
    }
}

Reducer

export default function reducer(state = {
    fetchedStorages: [],
    openAddStorageModal: false
}, action) {
    switch (action.type) {
        case "Fetch_Storage": {
            return {
                fetchedStorages: action.payload
            }
        }
        case "Load_Add_Storage_Modal": {
            return {  
                openAddStorageModal: action.payload,
                fetchedStorages: state.fetchedStorages
            }
        }
        case "New_Storage_Created": {
            return {
                openAddStorageModal: false,
            }
        }
    }


    return state;
}

AddStorageModal

import React from 'react';

import 'materialize-css/sass/materialize.scss';
import 'materialize-css/js/materialize.js';
import 'font-awesome/scss/font-awesome.scss';
import '../styles/main.scss';

export default class AddStorageModal extends React.Component {
    constructor() {
        super();
        this.state = {storageName: ""}
    }
    handleChange(event) {
       this.setState({storageName: event.target.value});
    }
    render() {
        if (this.props.storages.openAddStorageModal) {
            $('#add-new-storage-modal').openModal({ dismissible: false });
        }
        return (
            <div id="add-new-storage-modal" className="modal" >
                <div className="modal-content">
                    <h6>Enter your new Storage (Freezer, Pantry, etc.) </h6>
                    <div className="row">
                        <form>
                            <div className="input-field col s12 m12 l12 ">
                                <input id="storage_name" type="text" className="validate" value={this.state.storageName}  onChange={this.handleChange} />
                                <label htmlFor="storage_name">Storage Name</label>
                            </div>
                            <br />
                            <h4 className="center">OR</h4>
                            <h6>Enter in the sharing key you were given.</h6>
                            <div className="input-field col s12 m12 l12 ">
                                <input id="sharing_key" type="text" className="validate" />
                                <label htmlFor="sharing_key">Sharking Key</label>
                            </div>
                        </form>
                    </div>
                </div>
                <div className="modal-footer">
                    <a href="#!" className="waves-effect waves-green btn-flat left">Add</a>
                    <a href="#!" className="modal-action modal-close waves-effect waves-green btn-flat" onClick={() => this.props.loadAddStorageModal(false) }>Cancel</a>
                </div>
            </div>
        )
    }
}

I get

Uncaught TypeError: Cannot read property 'setState' of undefined

So I am not sure if this just means I am doing redux wrong or if I just made some general error.

Upvotes: 0

Views: 117

Answers (2)

Omri Aharon
Omri Aharon

Reputation: 17064

You can't pass a generic function reference, you need to keep the reference to this. You have 2 options:

  1. bind this to the function, like @nuway said in his answer.

  2. Use an arrow function, which also keeps the this reference: onChange={ (event) => this.handleChange(event) }

Upvotes: 2

nuway
nuway

Reputation: 2384

you need to bind to this for the handleChange handler, otherwise this inside handleChange funtion won't be the react component but rather the input element itself.

onChange={this.handleChange.bind(this)}

Upvotes: 0

Related Questions