erikras / multireducer

A utility to wrap many copies of a single Redux reducer into a single key-based reducer.
MIT License
422 stars 23 forks source link

Toggling object returns null #124

Closed jephjohnson closed 7 years ago

jephjohnson commented 7 years ago

I am using the same reducer logic in the read me. The idea is to toggle a class depending on which button you clicked on. Each event fires, but my object is not toggling. Any thoughts?

App:


import React from "react"
import { bindActionCreators } from 'multireducer';
import { connect } from "react-redux"
import Button from "./Button"
import * as toggleactionCreators from '../actions/toggleActions';

//const mapStateToProps = state => ({ hidden: state.toggleCollection });
const mapStateToProps = (state, { as }) => ({ hidden: state.toggleCollection[as] });
const mapDispatchToProps = (dispatch, { as }) => bindActionCreators({...toggleactionCreators}, dispatch, as)

class Main extends React.Component {

  toggleDiv() {
    this.props.toggleDiv();
    console.log(this.props)
  }

  render() {
    const { hidden } = this.props;
    return (
      <div>
      <Button as="toggleA" onClick={this.toggleDiv.bind(this)} />
      <Button as="toggleB" onClick={this.toggleDiv.bind(this)} />
      <div>
        <h3 as="toggleA" className={ hidden ? null : "toggled"} >Good Day!</h3>
        <h1 as="toggleB" className={ hidden ? null : "toggled"} >Hello There!</h1>
      </div>
    </div>
    )    
  }
}

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

toggleAction:

export const toggleDiv = () => {
  return {
    type: 'TOGGLE_DIV',
  }
}

toggleReducer:

const toggle = (state = { hidden: false}, action) => {
  switch(action.type) {
    case 'TOGGLE_DIV':
      return Object.assign({}, ...state, {hidden: !state.hidden});
    default:
      return state;
  }
};
export default toggle;

Index Reducer:

import multireducer from 'multireducer';
import { combineReducers } from "redux"
import toggle from "./toggleReducer"

const thereducer = combineReducers({
  toggleCollection: multireducer({
    toggleA : toggle,
    toggleB : toggle
  })
});

export default thereducer;
yesmeck commented 7 years ago

You should wrap Button and h1 to one component just like ListComponent in doc, then use the component in Main。

jephjohnson commented 7 years ago

@yesmeck - still not working. See Edit below.

App.js:

import React from "react"
import { bindActionCreators } from 'multireducer'
import { connect } from "react-redux"
import Button from "./Button"
import * as toggleactionCreators from '../actions/toggleActions'

const mapStateToProps = (state, { as }) => ({ hidden: state.toggleCollection[as] });
const mapDispatchToProps = (dispatch, { as }) => bindActionCreators({...toggleactionCreators}, dispatch, as)

class Main extends React.Component {

  toggleDiv() {
    this.props.toggleDiv();
  }

  render() {
    const { hidden } = this.props;
    return (
      <div>
        <Button as="toggleA" onClick={this.toggleDiv.bind(this)} hidden={ hidden } />
        <Button as="toggleB" onClick={this.toggleDiv.bind(this)} hidden={ hidden } />
      </div>
    )    
  }
}

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

Button.js:

import React, { Component, PropTypes } from 'react';

class Button extends React.Component {
  constructor() {
    super()
  }
  render() {
    const { hidden } = this.props
    console.log(this.props)
    return (
      <div>
        <button className="btn btn-info" onClick={this.props.onClick}>Button</button>
        <h1 className={ hidden ? null : "toggled"} >Hello There!</h1>
      </div>
    );
  }  
}

Button.propTypes = {
  onClickHandler: PropTypes.func,
  hidden: PropTypes.bool
};

Button.defaultProps = {
  onClickHandler: () => {},
  hidden:true
};

export default Button
jephjohnson commented 7 years ago

Bump

yesmeck commented 7 years ago

@jephjohnson You should connect Button, not Main, think of Button is a polymorphic component.

jephjohnson commented 7 years ago

Still no luck :(

yesmeck commented 7 years ago

Here is a example https://github.com/erikras/react-redux-universal-hot-example/pull/1343

jephjohnson commented 7 years ago

Same Approach, still no luck :/

Button.js

import React, { Component, PropTypes } from 'react';
import {connect} from 'react-redux';
import { toggleDiv } from '../actions/toggleActions';

@connect(
  (state, { as }) => ({hidden: state.toggleCollection[as].hidden}),
  {toggleDiv}
)

export default class Button extends Component {
  static propTypes = {
    hidden: React.PropTypes.bool
  }

  toggleDiv() {
    this.props.toggleDiv();
  }

  render() {
    const { hidden } = this.props
    console.log(this.props)
    return (
      <div>
        <button className="btn btn-info" onClick={this.toggleDiv.bind(this)}>Button</button>
        <h1 className={ hidden ? null : "toggled"}>Hello There!</h1>
      </div>
    );
  }  
}

App.js:

import React from "react"
import Button from "./Button"

class Main extends React.Component {
  render() {
    return (
      <div>
        <Button as="toggleA" />
        <Button as="toggleB" />
      </div>
    )    
  }
}
export default Main
yesmeck commented 7 years ago

use import { bindActionCreators } from 'multireducer' to bind action creators.

jephjohnson commented 7 years ago

You are a legend, thank you for being patient with me on this. 💯

Final solution if anyone needs it. Button.js

import React, { Component, PropTypes } from 'react';
import {connect} from 'react-redux';
import { toggleDiv } from '../actions/toggleActions';
import { bindActionCreators } from 'multireducer';

const mapStateToProps = (state, { as }) => ({ hidden: state.toggleCollection[as].hidden });
const mapDispatchToProps = (dispatch, { as }) => bindActionCreators({toggleDiv}, dispatch, as)

class Button extends Component {
  static propTypes = {
    hidden: React.PropTypes.bool
  }

  toggleDiv() {
    this.props.toggleDiv();
  }

  render() {
    const { hidden } = this.props
    console.log(this.props)
    return (
      <div>
        <button className="btn btn-info" onClick={this.toggleDiv.bind(this)}>Button</button>
        <h1 className={ hidden ? null : "toggled"} >Hello There!</h1>
      </div>
    );
  }  
}
export default connect(mapStateToProps, mapDispatchToProps)(Button);