Skip to content
Advertisement

Duplicate components in React after click button

REACT Problem – I would like to do something like this to start the function of creating a new component after clicking on the button. Moreover I want the div element with its content to appear every time I click a button. (in my case my own component)

For example when i want to create questionnaire and add questions i need a button who let me add input for this question. You know, duplicate components.

“REACT.CreateElement”? which will be in some loop? Or maybe there are other methods do you know?

I tryed CreateElement, customElements.define() but i dont know it is correct way. Now i;m traing use. Can you help me? Thank you in advance, Below my code:

**import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import DV from 'components/dataView/DataView'
import FieldsWrapper from 'components/fieldsWrapper/FieldsWrapper'
import FormMetaObject from 'components/form/components/form/FormMetaObject'

import Card from "components/card/Card"
import {Combobox} from  'components/form/components/combobox/Combobox'
import InputText from 'components/form/components/input/InputText'
import InputDateTime from 'components/form/components/input/InputDateTime/InputDateTime'
import { Checkbox } from 'components/form/Form';
import EnumListView from 'components/form/components/enumList/EnumListView'
import Button from 'components/button/Button';

const AddQ = () => {
    const [numberOfQuestion, setNumberOfQuestion] = useState(0);
 
 
    return <div>
       { setNumberOfQuestion(number => number++)}
       {console.log("FEUF")}
       {Array(numberOfQuestion).fill("").map((_, id) => <Questionnaire />)}
    </div>
}


const Questionnaire = ({data}) => {
    const {title} = data || {}

    return(
        <div>{`Tytuł: ${title}`}</div>
    )
}

const DataProvider = ({children}) => {
   const [state, setState] = React.useState([]);
   const url = "https://60226fc4ae8f8700177df76f.mockapi.io/api/v1/users/1/questionnaire"
   fetch(url)
   .then(response => response.json())
   .then(data => setState(data));

  return (
     
   <FormMetaObject
   
            data={{
                meta: {
                    dataType: 'text',
                    attributes: {
                        Login: {
                            name: 'Login',
                            label: 'adam',
                            type: 'String',
                            validations: [{ type: 'Required' }]
                        },
                    }
                },
                data: [
                    {
                        attributes: {
                        }
                    }
                ]
            }}
        >
 {children}
        </FormMetaObject>
  )}

function Content() {
   const [state, setState] = React.useState([]);
   const url = "https://60226fc4ae8f8700177df76f.mockapi.io/api/v1/users/1/questionnaire"
   fetch(url)
   .then(response => response.json())
   .then(data => setState(data));

   const values = [
        { id: 1, value: 'marketing' },
        { id: 2, value: 'IT' },
        { id: 3, value: 'tłumacze' },
        { id: 4, value: 'księgowość' },
        { id: 5, value: 'zarządzanie ' }
    ]
    const selected = []
    function onChange() { }

   return(
      <Card>
            <h4>Nowa ankieta</h4>
            <FieldsWrapper>
                <InputText name="Tytuł" />
                <InputText name="Opis" />
                <InputDateTime name ="Data rozpoczęcia ankiety"/>
                <InputDateTime name ="Data zakończenia ankiety"/>
            </FieldsWrapper>
            <FieldsWrapper>
                <Checkbox name ="Obowiązkowa"/>
                <Checkbox name ="Anonimowa"/>
                <Checkbox name ="Czy ankieta ma być wysłana do autora ankiety? "/>
            </FieldsWrapper>
                <EnumListView name ="do kogo ma trafić ankieta" values={values} selected={selected} onChange={onChange} />
            <FieldsWrapper>
                <Button color="link" onClick={() =>AddQ()}>Add</Button>
            </FieldsWrapper>
            <div id="ankieta" ></div>
     </Card>
         )}**

Advertisement

Answer

There’s quite a few things wrong here.

Firstly, be careful what you do in the body of a component. This will run every time the component renders. So firstly wrap your fetch in a useEffect:

useEffect(() => { ... fetch logic}, []) // < empty dependency array

This will ensure the code only runs once when the component renders.

Also if you are updating state based on a return of a promise (like you are here), you should check the component is still mounted, before setting state. You can do this yourself, or there are libraries (react-use) for this.

Next… to repeat components, this is basic and common use case. Most commonly, you would have your questions represented as an array, and loop through this to generate the components. A very contrived example:

const listOfQuestions = [
  "What time is it?",
  "Can I ask a follow up?"
]

listOfQuestions.map((question, index) => (
  <Question key={index}>{question}</Question>
))

This will render as many <Question /> components as what is in the array listOfQuestions. This could be an array of objects with a more complex structure, but the concept is the same. You just loop through an array and conditionally render your component. When you do this, every component needs a unique key prop, so that React knows what to do at re-rendering.

The array listOfQuestions could be a stateful value (useState()) that you update dynamically. When you do this, the rendered components will update to reflect the new values in the array.

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement