1

I'm mapping over each object inside the array of objects inside my state's item property. The issue is, I want to be able to attach a button to each returned item that only works with that item, and not the other items too. Here's what I have so far:

class App extends React.Component {
    state = {
        item: [],
    }
    componentDidMount() {
        this.setState({
            item: [
                {
                    name: 'jacob',
                    hair: 'brown',
                    sex: 'male',
                }, {
                    name: 'hannah',
                    hair: 'brown',
                    sex: 'female',
                }
            ]
        })
    }
    handleChange = (e) => {
        console.log(e.target.value)
        var x = Object.assign({}, this.state)
    }
    render() {
        return(
            <div>
                { this.state.item.length > 0 ? 
                    (
                        <div className="row mt-5">
                            <Item item={ this.state.item } handleChange={ this.handleChange } />
                        </div>
                    ) : null
                }
            </div>
        )
    }
}

class Item extends React.Component {
    render() {
        return(
            <div className="col">
                { this.props.item.map(s => (
                    <div>
                        <div className="mt-5">{ s.name }</div>
                        <button onClick={ this.props.handleChange } value={ s.name }>Click</button>
                    </div>
                 ))}
            </div>
        )
    }
}

So for instance, if the button's fx was to change the name property of the item it was rendered with, I want it to only change that item and no other items should be affected. Whenever I iterate through it attaches the button's fx to every item, so if I click it for one, I'm really clicking it for all of them, and that's exactly what I don't want.

For those curious, I'm setting the state in componentDidMount to simulate calling an API.

Also, the fx that's currently running in the handleChange is just some messing around I was doing trying to figure out values and a solution to manipulating a nested object inside an array.

2 Answers 2

1

Try this refactored code on CodeSandBox, You have to add keys when iterating Components in React, i've added it, also the Item Component could be function Component since it doesn't handle a state.

Updated: below is the code in case it wouldn't be available on codesandbox.

import React from 'react';
import { render } from 'react-dom';

class App extends React.Component {
  state = {
    items: [],
  }

  componentDidMount() {
    this.setState({
      items: [
        {
          name: 'jacob',
          hair: 'brown',
          sex: 'male',
        }, {
          name: 'hannah',
          hair: 'brown',
          sex: 'female',
        }
      ]
    })
  }

  handleChange = (e) => {
    console.log(e.target.value)
  }

  render() {
    const { items } = this.state;
    return (
      <div>
        {items.length && (
          items.map((item, index) => (
            <div className="row mt-5" key={index}>
              <Item item={item} handleChange={this.handleChange} />
            </div>
          ))
        )
      }
      </div>
    )
  }
}

const Item = ({ item, handleChange }) => (
  <div className="col">
    <div className="mt-5">{item.name}</div>
    <button onClick={handleChange} value={item.name}>Click</button>
  </div>
);

render(<App />, document.getElementById('root'));
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the quick answer! I was thinking I'd probably have to use keys, but how would I go about actually accessing that key? For instance, how would I console.log the name value of the second element, or in other words console.log "hannah?"
@JacobLockett, you could see the console in codesandbox! just click on it.
1

I think you want to pass the individual element in to your handleChange:

  { this.props.item.map((s, i) => {
      <div>
        <div className="mt-5">{ s.name }</div>
        <button key={i} onClick={ (s) => this.props.handleChange(s) } value={ s.name }>Click</button>
      </div>
   })}

This way, you will have the individual item passed in as an argument, so when you are writing your handleChange, you can do whatever you want with just that item and not the whole array.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.