1

for my sample project, I'm trying something in ReactJs in which I'll take several values and split them into two objects or more. I don't have much experience with reactjs, so if you have any examples or websites that can help me improve my reactjs skills, or any advise you can give me, I'd appreciate it. If there is anything you don't understand or need clarified, please leave a comment below.

enter image description here

When I submit, it just displays the blue and medium values, which makes sense because my code doesn't allow for multiple value input. Is there any way to fix this or improve it? I wanted to test it after two multiple inputs of each, thus I want to build it some type of dynamic multiple inputs that not only manages two same category values like red and blue, but also handles three inputs of the same color category.

Code


import React, { useState } from "react";
import { Button, Form, Grid } from "semantic-ui-react";

function Sample() {
  const [attributes, setAttributes] = useState([]);
  const [color, setColor] = useState("");
  const [size, setSize] = useState("");

  const onSubmit = () => {
    setAttributes([
      ...attributes,
      {
        id: new Date().getTime() + attributes.length,
        color: color,
        size: size,
      },
    ]);
    setColor("");
    setSize("");
  };

  console.log(attributes);

  return (
    <>
      <Form onSubmit={onSubmit}>
        <h2>Create a Child Attributes:</h2>

        <Form.Field>
          <Grid columns={2}>
            <Grid.Row>
              <Grid.Column>
                <Form.Input
                  placeholder="Please Enter Color"
                  name="color"
                  label="Color: "
                  onChange={(event) => {
                    setColor(event.target.value);
                  }}
                />
                <Form.Input
                  placeholder="Please Enter Color"
                  name="color"
                  label="Color: "
                  onChange={(event) => {
                    setColor(event.target.value);
                  }}
                />
              </Grid.Column>
              <Grid.Column>
                <Form.Input
                  placeholder="Please Enter Size"
                  name="size"
                  label="Size: "
                  onChange={(event) => {
                    setSize(event.target.value);
                  }}
                />
                <Form.Input
                  placeholder="Please Enter Size"
                  name="size"
                  label="Size: "
                  onChange={(event) => {
                    setSize(event.target.value);
                  }}
                />
              </Grid.Column>
            </Grid.Row>
          </Grid>
          <br />
          <Button type="submit" color="teal">
            Submit
          </Button>
        </Form.Field>
      </Form>

      <table className="ui celled sortable table">
        <thead>
          <tr>
            <th>ID</th>
            <th>Color</th>
            <th>Size</th>
          </tr>
        </thead>
        <tbody>
          {attributes.map(({ id, color, size }) => (
            <tr key={id}>
              <td>{id}</td>
              <td>{color}</td>
              <td>{size}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </>
  );
}

export default Sample;

Code sandbox => https://codesandbox.io/s/affectionate-mayer-1ecqw?file=/src/App.js

2
  • What do you expect when click on submit to happen? To add a new entry to the table or add the values to the same row with comma-separated multiple values? Commented Dec 5, 2021 at 11:17
  • Hi, thanks for ur comment I wanted when I click on submit I wanted it to add new entry to the table not one row that is separated by a comma Commented Dec 5, 2021 at 11:54

1 Answer 1

1

Typically, dealing with objects/array via state requires extra abstraction. In the case of having an array of items, the best practice is to create a child component for an object and pass the whole array item into it, plus onChange callback which returns a new object.

An additional point that can be helpful - is using controlled inputs. So the main difference is to set up an initial object for each form section. Here is an official explanation https://reactjs.org/docs/forms.html

Here is the straightforward solution with the following changes:

  • callback updated to have a middleware to deal with state
  • other state hooks are deleted (as far as I understand the situation)
  • onSubmit is empty, but there is actual attributes in state
import React, { useState } from "react";
import { Button, Form, Grid } from "semantic-ui-react";

function Sample() {
  const [attributes, setAttributes] = useState([{}, {}]);

  const onSubmit = () => {
    console.log(attributes);
  };

  const onFieldChange = (index, name, value) => {
    setAttributes(
      attributes.map((a, i) => (i !== index ? a : { ...a, [name]: value }))
    );
  };

  return (
    <>
      <Form onSubmit={onSubmit}>
        <h2>Create a Child Attributes:</h2>

        <Form.Field>
          <Grid columns={2}>
            <Grid.Row>
              <Grid.Column>
                <Form.Input
                  placeholder="Please Enter Color"
                  label="Color: "
                  onChange={(event) => {
                    onFieldChange(0, "color", event.target.value);
                  }}
                />
                <Form.Input
                  placeholder="Please Enter Color"
                  label="Color: "
                  onChange={(event) => {
                    onFieldChange(0, "size", event.target.value);
                  }}
                />
              </Grid.Column>
              <Grid.Column>
                <Form.Input
                  placeholder="Please Enter Size"
                  label="Size: "
                  onChange={(event) => {
                    onFieldChange(1, "color", event.target.value);
                  }}
                />
                <Form.Input
                  placeholder="Please Enter Size"
                  label="Size: "
                  onChange={(event) => {
                    onFieldChange(1, "size", event.target.value);
                  }}
                />
              </Grid.Column>
            </Grid.Row>
          </Grid>
          <br />
          <Button type="submit" color="teal">
            Submit
          </Button>
        </Form.Field>
      </Form>

      <table className="ui celled sortable table">
        <thead>
          <tr>
            <th>ID</th>
            <th>Color</th>
            <th>Size</th>
          </tr>
        </thead>
        <tbody>
          {attributes.map(({ id, color, size }) => (
            <tr key={id}>
              <td>{id}</td>
              <td>{color}</td>
              <td>{size}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </>
  );
}

export default Sample;

And here is the playground to play with the code: https://codesandbox.io/s/gracious-rgb-suf6k?file=/src/App.js

Please let me know in case of any questions/misunderstandings from my side.

Sign up to request clarification or add additional context in comments.

2 Comments

Hello thanks for answering this is what I needed but the problem is the input of 0 and 1s onFieldChange is there a way to make this dynamic?
Sure, if you have a dynamic list then you can use items.map((item, index) => <Grid row... - and use the index there

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.