Accessing the state from a child functional component and then adding it to an array of objects in the parent component

I'm facing a challenge with a parent component that needs to manage the data of its child components stored in an array of objects. My goal is to add new child components and maintain their information within the parent's state as an array of objects. I need guidance on how to achieve this, especially when it comes to both tracking the objects in the state and retrieving content from the children.

The structure includes:

const Parent: React.FC = () => {
  const [children, setChildren] = React.useState(
    [ 
      {
        id:1, 
        name:'',
        age:0,
      }
    ]
  );
  const getChildName = () => {
     // uncertain about accessing the new child
  } 

  // Adding a new child
  const AddChild = () => {
    let tmpid = children[children.length].id + 1; // unsure if this approach is correct
    setChildren(
      [
        ...children, 
        {
          id:tmpid,
          name:' ',
          age:0,
        }
      ]
    )
  }
  return (
    <button onClick={this.addChild}>Add component</button>
    {
      children.map((child) => (
        <NewChild key={child.id} getChildName={getChildName} getChildAge={getChildAge}/>
      ))
    }
  )
}

Additionally, there is a basic child component involved:

interface IChild {
  name?: string;
  age?: number;
}

type Props = {
  getChildName : void,
  getChildAge : void,
}

const NewChild: React.FC<Props> = (Props) => {
  const [child, setChild] = React.useState<Partial<IChild>>({});

  return (
    <input value={child?.name??''} onChange={e => setChild({...child , child: e.target.value})}/>
    <input value={child?.age??''} onChange={e => setChild({...child , child: parseFloat(e.target.value)})}/>

  )
}

Answer №1

Check out my implementation of getChildName below. It hasn't been tested, but I believe it should function correctly. Make sure to also read the comments within the code. If you need to implement getChildAge, you can follow a similar approach as with getChildName, but return newChild.age instead.

const Parent: React.FC = () => {
  const [children, setChildren] = React.useState(
    [
      {
        id:1,
        name:'',
        age:0,
      }
    ]
  );
  const getChildName = (id: number) => {
     let newChild = null;

     children.forEach((child) => {
         if (child.id == id) {
             newChild = child;
         }
      }
      return !!newChild ? newChild.name : `No child was found with id ${id}`
  }

  // Add a new child
  const AddChild = () => {
    /* let tmpid = children[children.length].id + 1; -- this will work. */
    let tmpid = children.length + 1 // This is cleaner, and as long as your id starts on 1,
                                    // this will be the exact same result.
    setChildren(
      [
        ...children,
        {
          id:tmpid,
          name:' ',
          age:0,
        }
      ]
    )
  }
  return (
    <button onClick={this.addChild}>Add component</button>
    {
      children.map((child) => (
        // You need to add return here.
        return <NewChild key={child.id} getChildName={(child.id) => getChildName(child.id)} getChildAge={getChildAge}/>
      ))
    }
  )
}

As johnrsharpe mentioned, avoid managing the same state in multiple locations. Provide NewChild with a callback like this:

<NewChild // Inside Render() method of <Parent />
   key={child.id} 
   getChildName={(child.id) => getChildName(child.id)} 
   getChildAge={getChildAge} 
   callback={updateChildren}
/> 

const updateChildren = (inputChild: IChild) => {  // Method of <Parent />
     const newChildren = children.map((child) => {
         if (child.id = inputChild.id) {
             child.name = inputChild.name;
             child.age = inputChild.age;
         }
         return child;
     }

     setChildren([ ...newChildren ]);
}

In the NewChild component, instead of using setChild state, pass the object into a function like this:

const changeChildProperty = (value: any) => {
    // update property of child

    // Pass in the entire child object, and it will be updated in parent state through the callback
    props.callback(child);
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

React Weather App experiencing issues with prop communication and updating variables

My innovative weather app allows users to input custom longitude and latitude coordinates. Once the coordinates are received, they are passed as props to a child component where they are used in an API call to fetch data for that specific area. While ever ...

What is the reason for PeerJs altering a MediaStream before transmitting it to another person?

I am currently developing a video chat application using Next.js 14, Express, socket.io, and peerjs One issue I am encountering is that when I send a stream, the user receives a modified version of it. This occurs specifically when I enter a room with my ...

Error in React + Jest unit test caused by Material-UI typography issue

When I run my React web app in the browser, no warnings are displayed. However, when running unit tests, I am encountering a Material-UI typography error. Warning: Material-UI: you are using the deprecated typography variants that will be removed in the ...

Check out the attributes of a class

I have a TypeScript class that is defined like this: export class MyModel { ID: number; TYPE_ID: number; RECOMMENDED_HOURS: number; UNASSIGNED_HOURS: number; } In a different .ts file, I instantiate this class within a component: export class My ...

When I execute `npm install`, what does the error message `npm ERR! ERESOLVE could not resolve` indicate?

My current version of node.js is 18.12.0 and npm is at 8.19.2. When I attempt to run npm install, an error is displayed: https://i.stack.imgur.com/uppdj.png I am able to bypass the error by using --force, but this leads to a dependency tree issue. ...

Tips for enhancing filtering functionality in ReactJS

Is there a way to create a filter that will only display matching elements when the letters in first_name and last_name strictly match the beginning of the names? const filterContacts = ({first_name, last_name}) => { return first_name.toLocaleLowerC ...

What methods are available to expedite webpack compilation (or decouple it from server restart)?

My current setup includes the following configurations: import path from 'path' import type {Configuration} from 'webpack' const config: Configuration = { mode: 'development', entry: path.join(__dirname, '../..&apos ...

Checkbox selections persist when navigating between pages

I am currently working with Angular 9 and I have a list of checkboxes that need to default to true when displaying certain data. If one of these checkboxes is unchecked, it should trigger the display of specific information. The issue I am facing is that o ...

ReactJS bug: Array rendering problem affected by recent changes

Why does ReactJS remove the first element instead of the middle element when using array.splice to remove an element from an array? This is my code. I am using Redux as well. const reducerNotesAndLogin = (state = initialState, action) => { var tableNo ...

Bug in timezone calculation on Internet Explorer 11

I've spent hours researching the issue but haven't been able to find any effective workarounds or solutions. In our Angular 7+ application, we are using a timezone interceptor that is defined as follows: import { HttpInterceptor, HttpRequest, H ...

Error in MUI: Unable to access undefined properties (reading 'drawer')

Recently, I encountered an unexpected error in my project using MUI v5.0.2. Everything was working fine just a week ago with no errors, but now I'm facing this issue without any changes made to the code: Error: TypeError: Cannot read properties of un ...

Is there a way to customize the text "Number of rows" displayed in material UI TablePagination component?

Is it possible to customize the text "Rows per page" within the Material UI TablePagination component? I have searched everywhere without success... My goal is simply to translate it into Portuguese for my website. ...

Learn the steps to establish a one-to-many relational record with the help of Node.js and Sequelize-Typescript

Currently, I am working on Nodejs with sequelize-typescript to develop a CRUD system for a one-to-many relationship. Unfortunately, I have encountered an issue with my code that I cannot seem to pinpoint. While I am able to retrieve records successfully us ...

The observer error silently assumes an undefined type

Currently, I am attempting to implement the guidance provided in this Stack Overflow post on performing a File Upload using AngularJS 2 and ASP.net MVC Web API. The issue arises from the upload.service.ts file where an error is identified next to the prob ...

Customizing styles in Material UI by utilizing the Root component and the ClassName attribute

Exploring material UI for the first time has been quite enlightening. One interesting discovery I made is that styles in material UI can be customized by using the rule names of classes. For instance, if there's an element like MenuItem where I only ...

Error: The data received from the Axios GET request cannot be assigned to the parameter type of SetState

Currently I am in the process of building my initial TypeScript application after transitioning from a JavaScript background. While I am still adjusting to the concept of declaring types, there is a specific issue I am encountering at the moment. The sni ...

Merging an unspecified number of observables in Rxjs

My latest project involves creating a custom loader for @ngx-translate. The loader is designed to fetch multiple JSON translation files from a specific directory based on the chosen language. Currently, I am implementing file loading through an index.json ...

Resolving Discrepancies in Microfrontend Styling

Hey there, I'm currently dealing with a Microfrontend application that utilizes the Material UI dependency internally (both at the Host and Child MFE). I've encountered a CSS conflict problem that arises when the styles are loaded in a specific ...

Selecting menu items in React Material UI with various background colors using the RAL color selector component

Seeking a solution to create a component for selecting RAL colors using Material UI's TextField and MenuItem. Each item in the menu should have a background color reflecting the RAL color it represents. However, Material UI no longer supports inline s ...

Unable to successfully log out from next-auth using the Keycloak provider

I am currently using next-auth with my Next.js application to handle authentication. Here is how I have configured it: .... export default NextAuth({ // Configure one or more authentication providers providers: [ KeycloakProvider({ id: ' ...