skip to Main Content

I have app where I get some data from the API. Then I put this data into array named "data". Then this "data" array is converted to array of components named "elements" (array with child components generated by data from "data" array). When you press "add" button it add new blank data to "data" array then useEfect cast updateElemets function which creates child components with this data and put this components in "elements" array. I created testfunc casted by pressing save button and it console.log’s content of "elements" array. This same thing do function "handleDelete" from child component but it throws array without one element.

Here you can try it out and see what I am talking about: https://react-tw6smz.stackblitz.io

Child component:

const CategoryField = (props) => {
  const [label, setLabel] = useState(props.data.label);
  const [categoryId, setCategoryId] = useState(props.data.categoryId);
  const [description, setDescription] = useState(props.data.description);
  const [uniqueName, setUniqueName] = useState(props.data.uniqueName);

  return (
    <Row className="categoryBox">
      <Col xs={12}>
        <Row>
          <Col xs={12} className="categoryLabel">
            {label}
          </Col>
        </Row>
        <Row>
          <Col xs={4} className="categoryFieldTitle">
            categoryId:
            <input
              id="categoryId"
              onChange={(e) =>
                props.handleChange(e.target.value, props.id, e.target.id)
              }
              defaultValue={categoryId}
              className="categoryInput"
            />
          </Col>
          <Col xs={8} className="categoryFieldTitle">
            description:
            <input
              id="description"
              onChange={(e) =>
                props.handleChange(e.target.value, props.id, e.target.id)
              }
              defaultValue={description}
              className="categoryInput"
            />
          </Col>
        </Row>
        <Row>
          <Col xs={4} className="categoryFieldTitle">
            uniqueName:
            <input
              id="uniqueName"
              onChange={(e) =>
                props.handleChange(e.target.value, props.id, e.target.id)
              }
              defaultValue={uniqueName}
              className="categoryInput"
            />
          </Col>
          <Col xs={8} className="categoryFieldTitle">
            label:
            <input
              id="label"
              onChange={(e) => {
                setLabel(e.target.value);
                props.handleChange(e.target.value, props.id, e.target.id);
              }}
              defaultValue={label}
              className="categoryInput"
            />
          </Col>
        </Row>
        <Row>
          <Col xs={12}>
            <button
              className="categoryDeleteButton"
              onClick={(e) => props.handleDelete(props.id)}
            >
              Delete
            </button>
          </Col>
        </Row>
      </Col>
    </Row>
  );
};

Parent component:

export default function App() {
  const [data, setData] = useState([]);
  const [elements, setElements] = useState();

  const addBlank = () => {
    let tmp = [...data];
    tmp.push({
      uniqueName: 'unique_name',
      categoryId: 'category_id',
      description: 'some description',
      label: 'Nazwa',
    });
    setData(tmp);
  };
  const handleChange = (change, id, type) => {
    let tmp = [...data];
    switch (type) {
      case 'categoryId':
        tmp[parseInt(id)].categoryId = change;
        break;
      case 'description':
        tmp[parseInt(id)].description = change;
        break;
      case 'uniqueName':
        tmp[parseInt(id)].uniqueName = change;
        break;
      case 'label':
        tmp[parseInt(id)].label = change;
        break;
    }
    setData(tmp);
  };
  const handleDelete = (id) => {
    console.log(elements);
  };

  const updateElements = () => {
    let tab = [];
    for (let i = 0; i < data.length; i++) {
      tab.push(
        <CategoryField
          key={data[i].uniqueName.toString() + '' + i}
          data={data[i]}
          id={i}
          handleChange={handleChange}
          handleDelete={handleDelete}
        />
      );
    }
    setElements(tab);
  };
  useEffect(() => {
    console.log('changed elements');
    console.log(elements);
  }, [elements]);

  useEffect(() => {
    // const reqOptions = {
    //   method: 'GET',
    //   headers: {
    //     'Content-Type': 'application/json',
    //   },
    // };
    // fetch('http://127.0.0.1:5050/test', reqOptions)
    //   .then((res) => res.json())
    //   .then((dt) => {
    //     setData(dt);
    //   });
    setData([
      {
        uniqueName: 'test_name',
        categoryId: '434324324',
        description: 'Some desc',
        label: 'Test Name',
      },
    ]);
  }, []);
  useEffect(() => {
    updateElements();
  }, [data]);

  const testfunc = () => {
    console.log(elements);
  };

  return (
    <div className="main">
      <Container>
        <Row className="sectionTitleBox">
          <Col xs={12} className="sectionTitle">
            Categories
          </Col>
        </Row>
        {elements}
        <Row>
          <Col xs={12}>
            <button onClick={testfunc}>Save</button>
            <button onClick={addBlank}>Add</button>
          </Col>
        </Row>
      </Container>
    </div>
  );
}

When you click "add" you can see adding new element. "Save" button print content of "elements" array with my data. If you press "Delete" button it also prints "elements" array but without one element.

2

Answers


  1. Well, I see that this is a problem that can be solved with useContext, sharing the state and changing function between components

    Login or Signup to reply.
  2. Only thing I see wrong with your code is the handleDelete function is not actually changing the data state. You are only logging the current data, not changing it.

    Your handleDelete function should look like this:

    const handleDelete = (id) => {
        setData(prev => prev.filter(d => d.categoryId !== id))
    
      };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search