我正在使用 react hooks,遇到了一个问题,现在陷入了困境。
我有一个 json 数据,每当用户使用时我都会获取它logs in,因此我创建一个顶部栏来显示user names,当用户单击这些名称时,我会显示他们在数据库中创建或呈现的一些数据,这些数据我已经在数据中获取了
logs in
user names
我从服务器获取数据
let data= [ { "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" } ] } ]
我在侧面有一个按钮,我想在里面创建新的 div,其中包含我从顶部选择的名称。
假设我已经列出了,topbar并且总共有 3 个数据,即 3 个名称,因此如果数据长度小于 4,我正在做的事情是显示一个加号按钮来创建一个选项卡,这样用户可以创建一个选项卡,然后他们可以在每个选项卡里面创建一个 div,
topbar
我做了什么
我正在填充顶部栏,并且当我单击侧面按钮时,我正在div选定的选项卡内创建一个。
div
我面临的问题
我在这里链接了我的代码沙箱,这样就很容易理解我做了什么以及我想做什么
代码沙箱
在这里的代码沙箱中我已经编写了我的所有代码,请检查一下。
我已经解释了我正在尝试做的每一件事,我知道如何编码,但没有任何想法或方法。
如果没有用户的数据,那么我将从 1 开始为该用户创建选项卡和嵌套元素。
在每个新元素中都会有一个保存按钮,所以我会这样做,我唯一担心的是当我创建它们后从一个选项卡转到另一个选项卡时不要丢失用户界面上的数据
export default function App() { const [active_menu, setactive_menu] = useState(0); const [nestedData, setnestedData] = useState(null); let 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" } ] } ]; const Tab_click = (index, li) => { setactive_menu(index); setnestedData(li); }; const Create_element = () => { //here I don't know how to create new elements }; const addnewTab=()=>{ } return ( <div className="App row"> {data1.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={() => Tab_click(index, li)} > <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> ))} {data1.length < 4 && ( <span onClick={addnewTab} >ADD</span> )} <div className="col-11 col-sm-11 col-md-11 col-lg-11 col-xl-11"> <div className="row"> {nestedData !== null && nestedData.myData.map((li, index) => ( <div 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> ); }
这里您想要获取一个新名称,即页面上带有文本输入的表单,随机生成名称,使用提示,如下所示。调用setData并使用功能状态更新将现有数据扩展到新数组并附加新数据对象。
setData
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)]); } };
这里有几个事情要做。首先,您data1在函数主体中进行了定义,因此它会在每个渲染周期重置。保持数据处于状态,data可以作为初始状态提供。其次,您需要添加创建的元素。通过更新状态来执行此操作。
data1
data
移出data1组件并定义用(更新渲染中的所有引用)初始化的本地data组件状态data``data。
data``data
const [data, setData] = useState(data1);
与添加新选项卡的方法类似,获取新数据名称和标题。在这里我们调用setData并再次使用功能状态更新,但这次我们将现有状态映射到新数组。当数组索引与活动选项卡索引匹配时,这就是我们需要更新的数据对象。将其展开myData到新数组中并附加新数据对象。如果索引不匹配,则仅返回元素。
myData
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)) } };
此处的问题是由于保留了单独的状态对象而导致的nestedData,该对象仅在单击选项卡时才会更新。当新元素添加到活动选项卡的myData数组时nestedData不会更新。此处的解决方案是直接在 UI 中呈现嵌套数据。
nestedData
更新选项卡的 onClick 处理程序以简单地设置活动菜单(索引)。
onClick={() => setactive_menu(index)}
myData直接从新状态进行渲染data。
data[active_menu].myData.map((li, index) => (...
有条件地渲染 ADD 按钮将控制这一点。
{data.length < 4 && <button onClick={addNewTab}>ADD</button>}
完整代码
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://stackoverflow.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> ); }