更新时间:2023-02-04 21:08:37
Here you want to get a new name, i.e. a form on the page with a text input, random generate name, use a prompt as I did below. Call setData
and use a functional state update to spread existing data into a new array and append a new data object.
const addNewTab = () => {
/**
* window.prompt is just a quick way to request input from user.
*/
const name = window.prompt('Enter Name');
/**
* logic to generate next id, but could be anything really
*/
const id = generateId();
if (name) {
setData((data) => [...data, new Data(id, name)]);
}
};
div
should not gets deleted.A couple things going on here. First, you defined data1
in the function body so it is reset every render cycle. Keep the data in state, data
can be provided as initial state. Second, you need to add the created elements. Do this by updating state.
Move data1
out of the component and define local component state initialized with data
(update all references in render from data
to data
).
const [data, setData] = useState(data1);
Similar approach as adding a new tab, get the new data name and title. Here we call setData
and again use a functional state update, but this time we'll map the existing state to a new array. When the array index matches the active tab index this is the data object we need to updated. Spread its myData
into a new array and append the new data object. If index isn't a match then just return the element.
const Create_element = () => {
/**
* window.prompt is just a quick way to request input from user.
*/
const data_name = window.prompt('Enter Data Name');
const data_title = window.prompt('Enter Data Title');
if (data_name && data_title) {
setData(data => data.map((el, i) => i === active_menu ? {
...el,
myData: [...el.myData, { data_name, data_title }],
} : el))
}
};
Issue here is caused by keeping a separate nestedData
state object that is only ever updated when a tab is clicked. When a new element is added to the active tab's myData
array nestedData
isn't updated. Solution here is to simply render the nested data directly in the UI.
Update the tab's onClick handler to simply set the active menu (index).
onClick={() => setactive_menu(index)}
Render the myData
directly from the new data
state.
data[active_menu].myData.map((li, index) => (...
Conditionally rendering the ADD button will control this.
{data.length < 4 && <button onClick={addNewTab}>ADD</button>}
Full Code
import React, { useState } from "react";
import "./styles.css";
import RightBar from "./Right_option";
import NEsted from "./Nested";
import "bootstrap/dist/css/bootstrap.min.css";
/**
* https://***.com/questions/63814645/how-to-create-dynamic-elements-inside-global-tabs
*/
const data1 = [
{
id: 1,
name: "Maxi",
myData: [
{
data_name: "div1",
data_title: "div1 tittle"
},
{
data_name: "div1",
data_title: "div tittle"
}
]
},
{
id: 2,
name: "Phill",
myData: [
{
data_name: "div21",
data_title: "div21 tittle"
}
]
}
];
/**
* Data object constructor
* @param {number} id new data object id
* @param {string} name new data object name
* @example
* new Data(1, 'Bill')
*/
const Data = (id, name) => ({ id, name, myData: [] });
/**
* Id generator hook
* @param {number} [seed=0] initial id generator value
* @returns {function}
*/
const useIdGenerator = (seed = 0) => {
function* genId(seed = 0) {
let i = seed;
while (true) yield i++;
}
const generator = genId(seed);
return () => generator.next().value;
};
export default function App() {
const generateId = useIdGenerator(5);
const [data, setData] = useState(data1);
const [active_menu, setactive_menu] = useState(0);
const Create_element = () => {
/**
* window.prompt is just a quick way to request input from user.
*/
const data_name = window.prompt("Enter Data Name");
const data_title = window.prompt("Enter Data Title");
if (data_name && data_title) {
setData((data) =>
data.map((el, i) =>
i === active_menu
? {
...el,
myData: [...el.myData, { data_name, data_title }]
}
: el
)
);
}
};
const addNewTab = () => {
/**
* window.prompt is just a quick way to request input from user.
*/
const name = window.prompt("Enter Name");
if (name) {
setData((data) => [...data, new Data(generateId(), name)]);
}
};
return (
<div className="App row">
{data.map((li, index) => (
<div className="col-4 col-sm-4 col-md-3 col-lg-3 col-xl-3" key={index}>
<div
className={
index === active_menu
? "row dashboard_single_cont_active"
: "row dashboard_single_cont"
}
onClick={() => setactive_menu(index)}
>
<div className="dashboard_name col-10 col-sm-10 col-md-9 col-lg-10 col-xl-10">
{li.name}
</div>
<div
className={
active_menu === index
? "dashboard_option_active col-2 col-sm-2 col-md-3 col-lg-2 col-xl-2"
: "dashboard_option col-2 col-sm-2 col-md-3 col-lg-2 col-xl-2"
}
align="center"
></div>
</div>
</div>
))}
{data.length < 4 && <button onClick={addNewTab}>ADD</button>}
<div className="col-11 col-sm-11 col-md-11 col-lg-11 col-xl-11">
<div className="row">
{data[active_menu].myData.map((li, index) => (
<div
key={index}
className="col-11 col-sm-11 col-md-8 col-lg-6 col-xl-6"
>
<NEsted data={li} />
<br></br>
</div>
))}
</div>
</div>
<RightBar Create_element={Create_element} />
</div>
);
}