4

I want to pass a prop called verified through each map function and I am having difficulty setting it up.

UPDATE:

Passing verified to renderContinents works, but when add a parameter to renderCountry like this:

  {continent.countries.map(renderCountry(null, verified))}

My output is blank. Shouldn't this work though?

Updated code:

  const renderCities = cities => {
    return (
      <div>
        <label>
          <input
              onChange={onChange}
              type="checkbox"/>
        {cities.name}
        </label>
      </div>
    );
  };

  const renderCountries = ({country, verified}) => {
    console.log("came to country");
    return (
      <div className="city-location"> 
        <label>
            <input
              onChange={onChange}
              type="checkbox"/>
          {country.name}
        </label>
        {country.cities.map(renderCities)}
      </div>
    ); 
  };



function onChange(e) {
  console.log('checkbox verified:', (e.target.verified));
}


class AreasComponent extends Component {
      constructor(props) {
        super(props);
        this.state = { 
        };
        this.renderContinents = this.renderContinents.bind(this);
    }

  componentWillMount() {
    this.props.fetchAllAreas(); 
  }

  renderContinents(verified, continent) {
    console.log("came to continent");
      return(
        <div className="continent-location">
          <label>
            <input
              onChange={onChange}
                type="checkbox"/>
             {continent.name}
          </label>

          {continent.countries.map(renderCountries(null, verified))}

        </div>
    )
  } 


  render() { 
    if (!this.props.verified || !this.props.areas) {
      return <div>Loading Areas...</div>
    }
    return(
        <div> 
          {this.props.areas.map(this.renderContinents.bind(this, this.props.verified))}
        </div>
      );
    }
}

function mapDispatchToProps(dispatch){
  return bindActionCreators({ fetchAllAreas, checkArea}, dispatch);
}


function mapStateToProps(state) {
  return { areas: state.areas.all,
           verified:state.areas.verified
  };
}


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

My other problem is the onChange(e) function. It's global so it works when I click any checkbox, but I want to make it so that when onChange is clicked, it can take in a parameter and dispatch the action checkArea, which, to me means it has to be bound and should also be fed as a parameter. I tried this:

  {this.props.areas.map(this.renderContinents.bind(this, this.props.verified, this.props.checkArea))} 

but it returns a blank result. Is it possible to send a function into a map () parameter and is there a way to get renderCountry/renderCity to work with parameters?

lost9123193
  • 10,460
  • 26
  • 73
  • 113
  • This is a duplicate of http://stackoverflow.com/q/3800512/497418. Don't let the title fool you, it's a red herring of the underlying issue which is that you're calling the function immediately, rather than passing a function to be called. – zzzzBov Sep 02 '16 at 16:39

2 Answers2

5

When you .bind parameters, those parameters become the first value(s) passed to the function. You should have noticed that when looking at the console.log output.

I.e. when you do

var bar = foo.bind(this, x, y);
bar(z);

you get the values in this order:

function foo(x, y, z) {}

You have switch the order of parameters in your function:

renderContinent(checked, continent) {
  // ...
}

However, you can just keep the code you have. You don't have to pass the value to renderContinents.

In order to pass it to renderContinents etc, either .bind it or put the call inside another function:

continent.countries.map(renderCountries.bind(null, verified))
// or
continent.countries.map(country => renderCountries(country, verified))
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Thanks! I can now renderContinents. Just a quick question, what does the null parameter signify? When I used this code to renderCountries both country and verified appear to be null. I updated my code, thanks again! – lost9123193 Aug 30 '16 at 00:52
  • The null signifies the 'this' the function will be bound to. That is primarily what `.bind` is used for. But -as you can see-, it can also bind parameters. It can bind as many parameters as you like, but if you want to bind parameters, you're going to have to provide a 'this' as well. If you don't care what 'this' will be, null will do just fine. – Norbert Sep 06 '16 at 21:12
1

In fact, the simplest way for renderCountry/renderCity to call onChange() with checkArea action is to put them inside AreasComponent (i.e. as member functions). So they can access both onChange and checkArea.

class AreasComponent extends Component {
    constructor(props) {
        super(props);
        this.state = {};
        this.onChange = this.onChange.bind(this);
    }

    componentWillMount() {
        this.props.fetchAllAreas();
    }

    onChange(e, type) {
        console.log('checkbox verified:', this.props.verified);
        // call checkArea() here with your parameters
        this.props.checkArea(type);
    }

    renderCities(cities) {
        return (
            <div>
                <label>
                    <input
                        onChange={e => this.onChange(e, 'city')}
                        type="checkbox"/>
                    {cities.name}
                </label>
            </div>
        );
    };

    renderCountries(country) {
        console.log("came to country");
        return (
            <div className="city-location">
                <label>
                    <input
                        onChange={e => this.onChange(e, 'country')}
                        type="checkbox"/>
                    {country.name}
                </label>
                {
                    country.cities.map(this.renderCities)
                }
            </div>
        );
    };

    renderContinents(continent) {
        console.log("came to continent");
        return(
            <div className="continent-location">
                <label>
                    <input
                        onChange={e => this.onChange(e, 'continent')}
                        type="checkbox"/>
                    {continent.name}
                </label>
                {
                    continent.countries.map(this.renderCountries)
                }
            </div>
        )
    }

    render() {
        if (!this.props.verified || !this.props.areas) {
            return <div>Loading Areas...</div>
        }
        return(
            <div>
                {
                    this.props.areas.map(this.renderContinents)
                }
            </div>
        );
    }
}

function mapDispatchToProps(dispatch){
    return bindActionCreators({ fetchAllAreas, checkArea}, dispatch);
}


function mapStateToProps(state) {
    return {
        areas: state.areas.all,
        verified: state.areas.verified
    };
}


export default connect(mapStateToProps, mapDispatchToProps)(AreasComponent);
swen
  • 341
  • 1
  • 9
  • I actually figured this out 3 days ago but just gonna mark this as the correct answer since it was very similar to what I ended up doing. – lost9123193 Sep 04 '16 at 05:11