Search code examples
reactjscheckboxcheckboxlist

React.js Chakra UI multi-checkbox with use state


Hello everyone I am trying to implement a react.js checkboxes from an array and store the checked values in the state with the UseState hook. I am able to display the checkboxes but am unable to check and uncheck them. I am new to react and come from a Vuejs background and am used to the v-model sytax. Any help here would be great. Heres my code:

import React, { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useHistory, useLocation } from 'react-router-dom';
import {
  Box,
  Button,
  Checkbox,
  Table,
  Tbody,
  Td,
  Th,
  Thead,
} from '@chakra-ui/react';
import { Form, Input, message } from 'antd';
import styled from 'styled-components';
import useQueryParams from 'utilities/useQueryParams';

import useDelayedServiceCall from '../../../../utilities/useDelayedServiceCall';
interface FormValues {
  query: string;
}

interface SqlQueryRequest {
  query: string;
}

interface SqlQueryResponse {
  column_names: string[];
  rows: string[][];
}
const INITIAL_VALUES: FormValues = {
  query: '',
};
const initArray = [
  'First Name',
  'Middle Name',
  'Last Name',
  'Full Name',
  'Birthday',
  'Address',
  'Email',
  'Phone Number',
  'Ip Address',
  'Aliases',
  'Sign up date',
];
const newArray = initArray.map((item) => ({ value: item, checked: false }));
export default function SqlQueryForm() {
  const [checked, setChecked] = useState(newArray);
  const [array, setArray] = useState(newArray);
  const { t } = useTranslation([
    'actions',
    'common',
    'validations',
    'translation',
  ]);
  function handleCheck(e: any) {
    console.log('e', e);
    if (checked.includes(e.target.value)) {
      const index = checked.indexOf(e.target.value);
      checked.splice(index, 1);
    } else {
      setChecked([
        ...checked,
        {
          value: e.target.value.toString(),
          checked: Boolean(e.target.value.checked),
        },
      ]);
    }
  }
  const query = useQueryParams().get('query')?.trim();
  const history = useHistory();
  const location = useLocation();
  const [{ data, loading }, sqlQuery] = useDelayedServiceCall<
    SqlQueryResponse,
    SqlQueryRequest
  >(
    'franklin',
    'SqlQuery',
    undefined,
    (error) =>
      void message.error(t('common:events.error', { error: error?.message })),
  );
  const vertical = data?.rows[0]?.map((_, columnIndex) =>
    data.rows.map((row) => row[columnIndex]),
  );
  function handleFinish(values: FormValues) {
    const { query: newQuery } = values;
    const path = `${location.pathname}?query=${newQuery}`;
    history.replace(path);
    sqlQuery(values);
  }

  return (
    <>
      <p>
        The PII Reporter tool provides authorized personal access to customer
        PII information. All activity on this API is logged and access is
        reported. Elevated franklin privileges are required to perform the
        underlying actions.
      </p>
      <Box width="60vw">
        <Form>
          <Form.Item>
            <Input type="email" placeholder="email" />
          </Form.Item>
          <Form.Item>
            <Input.TextArea
              disabled={loading}
              rows={5}
              style={{ fontFamily: 'monospace' }}
            />
          </Form.Item>
          {newArray.map((item, index) => (
            <Checkbox
              key={Math.random()}
              {...item}
              onChange={handleCheck}
              isChecked={checked.toString().includes(item.value)}
            >
              {item.value}
            </Checkbox>
          ))}
        </Form>
      </Box>
    </>
  );
}

Solution

  • The problem was I wasn't copying the array by using JSON.parse keep this in mind when using arrays. You need to make deep copies... You could also use something like lodash and then save the newArray in the state.