Search code examples
javascriptreactjsreact-bootstrap

Unable to work out why the component reloads on Click


I am building a simple REACT app and using react-bootstrap's listgroup items.

App.js

import React from "react";
import "./App.css";
import { Container, Row } from "react-bootstrap";
import SimpleList from "./Containers/SimpleList";

function App() {
return (
    <div className="App">
    <Container>
        <Row className="justify-content-md-center">
        <SimpleList />
        </Row>
    </Container>
    </div>
);
}

export default App;

SimpleList.js

import React, { Component } from "react";
import { ListGroup, Form } from "react-bootstrap";

class SimpleList extends Component {
state = {
    items: [
    { checked: false, text: "Create example an Omniscient." },
    { checked: true, text: "Make it support es6!" },
    { checked: true, text: "And jsx!" },
    { checked: true, text: "It should compile as you type!" },
    { checked: true, text: "And give immediate feedback!" },
    { checked: false, text: "Make more examples!!" },
    ],
};

handleChange = (item) => {
    console.log("clicking checkbox for item", item);
};

render() {
    return (
    <form>
        <ListGroup>
        {this.state.items.map((item, i) => (
            <ListGroup.Item
            action
            onClick={() => this.handleChange(item)}
            variant="light"
            key={i}
            >
            <Form.Check
                type="checkbox"
                label={item.text}
                onChange={() => this.handleChange(item)}
            />
            </ListGroup.Item>
        ))}
        </ListGroup>
    </form>
    );
}
}

export default SimpleList;

When I click on the checkbox that is rendered from SimpleList the handleChange method is called but the app does not re-load. However when I click anywhere else on the Listgroup.item element, entire app is reloaded. Please can someone help me understand what is happening here and how to fix it. My main goal is that the end user should be able to click on the ListGroup.item or Checkbox in order to select the item on the checklist.


Solution

  • Edit: I now understand what you mean by saying "page reload", it's because ListGroup.Item is button and the default button action is to submit the form so it will reload the page. If we dont want it, we should use preventDefault() function. I just updated my answer with this here and in codesandbox too.

    As you may know, in react when you update your state the component will render again with your new state values.

    Lets changed your handleChange method to update your state like this:

    handleChange = (item, e) => {
        // This will prevent page load when you click on button
        e.preventDefault();
        // Get state values to the local variable
        const localItems = this.state.items;
        // Find the object index which I we want to update
        const itemIndex = localItems.findIndex(localItem => localItem === item);
        // Change our clicked item value with opposite
        item.checked = !item.checked;
        // Update our localItems array
        localItems[itemIndex] = item;
        // Then update our state with new Items array
        this.setState({ items: localItems });
    };
    

    Because we changed the state component will render again but this time our checkbox will be checked(or not checked)

    And change your render() method like this; remove onClick prop from Form.Check because ListGroup.Item is a wrap for your checkbox so when you click the checkbox you also clicked the ListGroup.Item too so there is no need for two onClick props. And we want to change that checkbox to make it mutable so we add checked prop and onChange method.

    return (
          <form>
            <div onClick={() => console.log(this.state.items)}>test</div>
            <ListGroup>
              {this.state.items.map((item, i) => (
                <ListGroup.Item
                  action
                  onClick={(e) => this.handleChange(item, e)}
                  variant="light"
                  key={i}
                >
                  <Form.Check
                    type="checkbox"
                    label={item.text}
                    checked={item.checked}
                    onChange={e => (e.target.checked = !e.target.checked)}
                  />
                </ListGroup.Item>
              ))}
            </ListGroup>
          </form>
        );
      }
    

    Working example is over here: codesandbox example

    I hope I could help :)