ScriptedChicken
ScriptedChicken

Reputation: 173

How can I create interactive checkboxes in my React JS app?

Description

I'm very new to React JS, which will probably show in my code. I'm trying to make a simple to-do app that will help me get my head around coding with React. The app should simply display "Complete" if a checkbox is checked and "Incomplete" if it isn't. However, the checkboxes aren't updating on click.

I think that the problem is to do with not understanding React logic, resulting in the Checkbox() function being called over and over with default variables (eg: checked == true).

Any advice would be appreciated!

Code and Examples

A screenshot as an example: enter image description here

File tree (excluding node_modules folder):

.
├── package.json
├── package-lock.json
├── public
│   └── index.html
└── src
    ├── App.js
    ├── Checkbox.js
    ├── index.css
    ├── index.js
    ├── TableBody.js
    ├── TableHeader.js
    └── Table.js

index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>React App</title>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import 'bootstrap/dist/css/bootstrap.min.css';

ReactDOM.render(<App />, document.getElementById('root'));

App.js

import { Component } from "react";
import Table from "./Table"

class App extends Component {
  render() {
    const tasks = [
      {
        status: "incomplete",
        task: "Wash Dishes"
      },
      {
        status: "complete",
        task: "Pat Dog"
      },
      {
        status: "incomplete",
        task: "Study"
      }
    ]

    return (
      <div>
        <Table tasks={tasks}/>
      </div>
    )
  }
}

export default App;

Table.js:

import TableHeader from "./TableHeader"
import TableBody from "./TableBody"
import { Component } from "react"

class Table extends Component {
    render () {
        const {tasks} = this.props
        return (
            <div className="table container">
                <TableHeader />
                <TableBody tasks={tasks}/>
            </div>

        )
    }
}

export default Table

TableBody.js

import Checkbox from './Checkbox'

const TableBody = (props) => {
    // takes the properties of the Table object and creates table rows by mapping
    // elements in the array. Returns a table body.

    const rows = props.tasks.map((row, index) => {
        return (
            <tr key={index}>
                <td><Checkbox /></td>
                <td>{row.task}</td>
            </tr>
        )
    })

    return <tbody>{rows}</tbody>
} 

export default TableBody

TableHeader.js

const TableHeader = () => {
    return (
        <thead>
            <tr>
                <th>Status</th>
                <th>Task</th>
            </tr>
        </thead>
    )
}

export default TableHeader

Checkbox.js

const checkStatus = (checked) => {
    var status = "Something's gone wrong."
    if (checked) {
        var status = "Complete"
    } else if (checked == false) {
        var status = "Incomplete"
    } else {
    }
    return status
}

const Checkbox = () => {
    const input = <input class="form-check-input" type="checkbox" checked></input>
    const status = checkStatus(input.props.checked)
    return (
        <div class="custom-control custom-textbox">
            {input}
            <label>{status}</label>
        </div>
    )
}

export default Checkbox

Upvotes: 1

Views: 515

Answers (1)

petarkolaric
petarkolaric

Reputation: 404

So you need some state so that your application can "remember" what state the checkbox should be in. That state will change based on whether the checkbox is clicked or not. At the moment, you are setting the checked status to always be true (so it will always appear to be checked). Try adding some state like this:

import React, { useState } from 'react';

...

const Checkbox = () => {

  const [isChecked, setIsChecked] = useState(false);
  const Input = (
    <input
      class="form-check-input"
      type="checkbox"
      checked={isChecked}
      onClick={() => setIsChecked(!isChecked) }
    />
    // You can self close tags in React fyi, unlike in HTML.
  ); 

  return (
        <div class="custom-control custom-textbox">
            <Input />
            <label>isChecked is set to: {isChecked}</label>
        </div>
  );
}

What's happening is that each time the checkbox is clicked, it changes the isChecked state to the opposite of what it currently is. If it is false it becomes true, and vice versa. You can then feed this value into other parts of your application, to actually use the checkbox's value (like in a server submit, for example).

I should probably mention - this uses the React useState hook. There are many other ways to introduce state management into your app, but this is probably the simplest one. You can read about it here: https://reactjs.org/docs/hooks-state.html

Upvotes: 1

Related Questions