So I want when the user clicks on the button, be able to create new CatagoryField
Component that I made. When I place the component in a function and call it it will only create the component once. I will appreciate some help. I’m confused about how should I implement this?
App components
import React, { useState } from "react"; import { Accordion, AccordionSummary, Chip, Button, IconButton, Autocomplete, TextField, } from "@mui/material"; import { Grid } from "@mui/material"; import SearchBar from "material-ui-search-bar"; import DeleteIcon from "@mui/icons-material/Delete"; import ExpandMoreOutlinedIcon from "@mui/icons-material/ExpandMoreOutlined"; import AddCircleOutlineOutlinedIcon from "@mui/icons-material/AddCircleOutlineOutlined"; import HelpIcon from "@mui/icons-material/Help"; import HistoryToggleOffIcon from "@mui/icons-material/HistoryToggleOff"; import AllMembers from "./components/common/main/allMembers"; import CatagoryField from "./components/common/main/catagoryField"; const autoCompleteOptions = [ { title: "A", year: 1994 }, { title: "B", year: 1972 }, { title: "C", year: 1974 }, { title: "D", year: 2008 }, { title: "E", year: 1957 }, { title: "F", year: 1993 }, { title: "G", year: 1994 }, ]; const App = () => { const [value, setValue] = useState(); const [element, setElement] = useState(0); const doSomethingWith = () => { return null; }; let i = 0; const creator = () => { while (i < element) { i++; return ( <CatagoryField catagoryName="خدماتی" react="از آنها چیزی میخریم" createdBy="سیستم" disable={false} /> ); } }; console.log(element); return ( <> <div style={{ margin: "4rem 1rem" }}> <Accordion> <AccordionSummary sx={{ height: "65px" }} aria-controls="panel1a-content" > <Grid container direction="row" justifyContent="space-between" alignItems="center" > <Grid item> <IconButton className="chevron__icon"> <ExpandMoreOutlinedIcon /> </IconButton> <span className="users__catagory"> دسته بندی کاربران</span> </Grid> <Grid item> <IconButton> <HistoryToggleOffIcon /> </IconButton> <IconButton> <HelpIcon className="help" /> </IconButton> <span className="version">4.3.2</span> </Grid> </Grid> </AccordionSummary> <AccordionSummary sx={{ height: "65px", padding: "30px", background: "#E6E6E6", cursor: "default !important", }} aria-controls="panel1a-content" > <Grid container direction="row" alignItems="center" sx={{ display: "relative" }} > <Grid item> <Button variant="outlined" sx={{ height: "50px" }} size="medium" onClick={() => setElement(element + 1)} endIcon={ <AddCircleOutlineOutlinedIcon sx={{ marginRight: "10px" }} /> } > افزودن دسته جدید </Button> </Grid> <Grid sx={{ width: "207px" }} item> <SearchBar className="search__holder" placeholder="جستجو..." value={value} style={{ width: "207px", height: "45px" }} onChange={(newValue) => setValue(newValue)} onRequestSearch={() => doSomethingWith()} /> </Grid> <Grid className="sort__field" item> <Autocomplete sx={{ width: "207px !important", padding: "0 !important", backgroundColor: "white !important", }} options={autoCompleteOptions} getOptionLabel={(option) => option.title} renderTags={(value, getTagProps) => value.map((option, index) => ( <Chip variant="outlined" label={option.title} {...getTagProps({ index })} /> )) } renderInput={(params) => ( <TextField {...params} variant="filled" sx={{ width: "207px !important", padding: "0 !important", background: "white !important", }} placeholder="مرتب سازی..." /> )} /> </Grid> <Grid item> <IconButton sx={{ margin: "0 5px" }}> <DeleteIcon /> </IconButton> </Grid> <Grid item className="last__edit"> <Grid item> <span> آخرین ویرایش: <a className="last_Modified" href="#"> سیستم </a> </span> <span>1405/12/24 23:59 </span> </Grid> </Grid> </Grid> </AccordionSummary> <AllMembers /> <CatagoryField catagoryName="اپراتور سیستم" react="اپراتور سیستم" createdBy="سیستم" /> <CatagoryField catagoryName="مشتریان" react="به آنها چیزی فروخته ایم" createdBy="سیستم" /> <CatagoryField catagoryName="خدماتی" react="از آنها چیزی میخریم" createdBy="سیستم" disable={false} /> {creator()} </Accordion> </div> </> ); }; export default App;
Advertisement
Answer
The best way in order to achieve the solution is to use a state with useMemo.and the problem with your code is that the creator acts as a function and it will only execute once try this.
import {useMemo} from 'react'; const App = () => { const [elements , setElements] = useState(0); const creator = useMemo(() => { return ( <> {Array(elements).fill(elements).map((item , index) => ( <CategoryField key={`cat-${index}`} // key is need when mapping! it is not props catagoryName="خدماتی" react="از آنها چیزی میخریم" createdBy="سیستم" disable={false} /> ))} </> ) },[elements]);//render when elements change return ( <> <div style={{ margin: "4rem 1rem" }}> <Accordion> <AccordionSummary sx={{ height: "65px" }} aria-controls="panel1a-content" > <Grid container direction="row" justifyContent="space-between" alignItems="center" > <Grid item> <IconButton className="chevron__icon"> <ExpandMoreOutlinedIcon /> </IconButton> <span className="users__catagory"> دسته بندی کاربران</span> </Grid> <Grid item> <IconButton> <HistoryToggleOffIcon /> </IconButton> <IconButton> <HelpIcon className="help" /> </IconButton> <span className="version">4.3.2</span> </Grid> </Grid> </AccordionSummary> <AccordionSummary sx={{ height: "65px", padding: "30px", background: "#E6E6E6", cursor: "default !important", }} aria-controls="panel1a-content" > <Grid container direction="row" alignItems="center" sx={{ display: "relative" }} > <Grid item> <Button variant="outlined" sx={{ height: "50px" }} size="medium" onClick={() => setElements(elements + 1)} endIcon={ <AddCircleOutlineOutlinedIcon sx={{ marginRight: "10px" }} /> } > افزودن دسته جدید </Button> </Grid> <Grid sx={{ width: "207px" }} item> <SearchBar className="search__holder" placeholder="جستجو..." value={value} style={{ width: "207px", height: "45px" }} onChange={(newValue) => setValue(newValue)} onRequestSearch={() => doSomethingWith()} /> </Grid> <Grid className="sort__field" item> <Autocomplete sx={{ width: "207px !important", padding: "0 !important", backgroundColor: "white !important", }} options={autoCompleteOptions} getOptionLabel={(option) => option.title} renderTags={(value, getTagProps) => value.map((option, index) => ( <Chip key={`chip-${index}`} variant="outlined" label={option.title} {...getTagProps({ index })} /> )) } renderInput={(params) => ( <TextField {...params} variant="filled" sx={{ width: "207px !important", padding: "0 !important", background: "white !important", }} placeholder="مرتب سازی..." /> )} /> </Grid> <Grid item> <IconButton sx={{ margin: "0 5px" }}> <DeleteIcon /> </IconButton> </Grid> <Grid item className="last__edit"> <Grid item> <span> آخرین ویرایش: <a className="last_Modified" href="#"> سیستم </a> </span> <span>1405/12/24 23:59 </span> </Grid> </Grid> </Grid> </AccordionSummary> <AllMembers /> <CatagoryField catagoryName="اپراتور سیستم" react="اپراتور سیستم" createdBy="سیستم" /> <CatagoryField catagoryName="مشتریان" react="به آنها چیزی فروخته ایم" createdBy="سیستم" /> <CatagoryField catagoryName="خدماتی" react="از آنها چیزی میخریم" createdBy="سیستم" disable={false} /> {creator} </Accordion> </div> </> ); } export default App;