Search code examples
javascriptarraysreactjsjavascript-objects

I have a component which is receiving data from the store. How can I update the data received and rerender the component on change


I have a store which gives me array of password objects For Example :

const passwords = [{
    id: 'hjgkjhkjl',
    password: 'jhckjdhf',
    createdAt: 'jan 3rd, 2019'
  },
  {
    id: 'uygkjhkj',
    password: 'kdjhfkjdhf',
    createdAt: 'jan 3rd, 2019'
  }
]

I can access this passwords in my component as this.props.passwords

I am trying to populate them on UI as a List with button(Update / Confirm) - I am toggling between them using a component level state

Since it is a component level state if I click on one button all the buttons are getting changed

Here is my code

class Passwords extends React.Component {

  constructor(props) {
    super(props)
    this.state = {
      disabled: false

    }
    this.handleUpdate = this.handleUpdate.bind(this)
  }

  handleUpdate(element) {
    // this.context.executeAction(removePassword, element.createdAt)
    // this.context.executeAction(fetchPasswords)
    this.setState({
      disabled: !this.state.disabled,
    })
  }

  render() {

    const data = [
      {
        password: "passwordone",
        createdAt: "Jan 2, 2019"
      },
      {
        password: "passwordtwo",
        createdAt: "Jan 2, 2019"
      }
    ];

    return (
      <div>
        {data.map((element) => {
          return (
            <div>
              <input value={element.password} disabled={!this.state.disabled}/>
              <span style={{marginLeft: "15px"}}> {element.createdAt} </span>
              <span style={{marginLeft: "15px"}}>
                <button onClick={() => this.handleUpdate(element)}> 
                  {this.state.disabled ? "Confirm" : "Update"}
                </button> 
              </span>
            </div>
          )
        })}
      </div>
    )
  }
}

ReactDOM.render(<Passwords/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root'>

</div>

Need a better approach to solve this

Working example is in the following Link

id are unique for the password items - expected result update/confirm need to be toggled only for clicked button

Thanks in advance


Solution

  • As sellmeadog said, you should create a parent component that will contain 2 components. Each component will have its own state, and the parent component will give each child its props. This way each button will have its own state, which means its own "disabled". In general it should look like that:

    class PasswordsContainer extends React.Component {
      constructor(props) {
        super(props);
        const data = [
          {
            password: 'passwordone',
            createdAt: 'Jan 2, 2019',
          },
    
          {
            password: 'passwordtwo',
            createdAt: 'Jan 2, 2019',
          },
        ];
    
        this.state = {
          disabled: false,
          data: data,
        };
        this.handleUpdate = this.handleUpdate.bind(this);
      }
    
      handleUpdate(element) {
        // this.context.executeAction(removePassword, element.createdAt)
        // this.context.executeAction(fetchPasswords)
        this.setState({
          disabled: !this.state.disabled,
        });
      }
    
      render() {
        return (
          <div>
            {this.state.data.map(element => {
              return <Password data={element} />;
            })}
          </div>
        );
      }
    }
    class Password extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          disabled: false,
          data: this.props.data,
        };
        this.handleUpdate = this.handleUpdate.bind(this);
      }
    
      handleUpdate(element) {
        this.setState({
          disabled: !this.state.disabled,
        });
      }
    
      render() {
        let element = this.state.data;
        return (
          <div>
            <input value={element.password} disabled={!this.state.disabled} />
            <span
              style={{
                marginLeft: '15px',
              }}>
              {' '}
              {element.createdAt}
            </span>
            <span
              style={{
                marginLeft: '15px',
              }}>
              <button onClick={() => this.handleUpdate(element)}>
                {this.state.disabled ? 'Confirm' : 'Update'}
              </button>
            </span>
          </div>
        );
      }
    }
    
    ReactDOM.render(<PasswordsContainer />, document.getElementById('root'));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
    <div id='root'>
    
    </div>

    please tell me if something is unclear