如何在全局选项卡中创建动态元素 [英] How to create dynamic elements inside global tabs

查看:20
本文介绍了如何在全局选项卡中创建动态元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 react hooks,遇到了一个我现在卡住的问题.

我有一个 json 数据,每当用户 logs in 时我都会得到它,因此我创建了一个显示 user names 的顶部栏,当用户单击这些名称时我正在显示他们在数据库中为他们创建或呈现的一些数据,我已经在数据中获取了这些数据

我从服务器获取的数据

 让数据= [{id":1,名称":马克西",我的数据":[{数据名称":div1",data_title":div1 标题"},{数据名称":div1",data_title":div 标题"}]},{id":2,姓名":菲尔",我的数据":[{数据名称":div21",data_title":div21 标题"}]}]

我有一个按钮,我想在上面创建新的 div,在我从顶部选择的名称内.

所以假设我已经列出了 topbar 并且总共有 3 个数据,即 3 个名称,所以如果数据长度小于 4 我在做什么,显示一个加号按钮来创建一个更多的选项卡,因此用户可以再创建一个选项卡,然后他们可以在每个选项卡中创建一个 div,

我做了什么

我正在填充顶部栏以及当我单击侧边按钮时,我正在所选选项卡内创建一个 div.

我面临的问题

  • 如果数据长度小于 4,我将提供一个加号按钮以在更多选项卡上创建(给它默认名称),但我不知道如何创建新的.
  • 当我单击侧边按钮在选项卡内创建一个潜水,然后转到另一个选项卡并再次返回时,我希望创建的 div 不应被删除.
  • 假设我有 3 个选项卡(数据),因此当页面加载我想要显示的第一个选项卡数据时,但它没有显示,我需要点击那里只显示它.
  • 如果数据为空,那么我最多可以创建 4 个标签,这也是我想要一些想法来做到这一点.

我将我的代码沙盒链接到这里,这样很容易理解我做了什么以及我想做什么

完整代码

import React, { useState } from "react";导入./styles.css";从./Right_option"导入RightBar;从./Nested"导入NEsted;导入bootstrap/dist/css/bootstrap.min.css";/*** https://stackoverflow.com/questions/63814645/how-to-create-dynamic-elements-inside-global-tabs*/常量数据1 = [{编号:1,名称:马克西",我的数据:[{数据名称:div1",数据标题:div1 标题"},{数据名称:div1",数据标题:div 标题"}]},{编号:2,名称:菲尔",我的数据:[{数据名称:div21",数据标题:div21 标题"}]}];/*** 数据对象构造器* @param {number} id 新数据对象id* @param {string} name 新数据对象名称* @例子* 新数据(1,'账单')*/const 数据 = (id, name) =>({ id, name, myData: [] });/*** ID 生成器钩子* @param {number} [seed=0] 初始 id 生成器值* @returns {函数}*/const useIdGenerator = (seed = 0) =>{功能* genId(种子= 0){让我=种子;while (true) yield i++;}const 生成器 = genId(seed);返回 () =>generator.next().value;};导出默认函数 App() {const generateId = useIdGenerator(5);const [data, setData] = useState(data1);const [active_menu, setactive_menu] = useState(0);const Create_element = () =>{/*** window.prompt 只是一种向用户请求输入的快捷方式.*/const data_name = window.prompt(输入数据名称");const data_title = window.prompt(输入数据标题");if (data_name && data_title) {setData((数据) =>data.map((el, i) =>我 === active_menu?{……额,myData: [...el.myData, { data_name, data_title }]}: el));}};const addNewTab = () =>{/*** window.prompt 只是一种向用户请求输入的快捷方式.*/const name = window.prompt(输入名称");如果(姓名){setData((data) => [...data, new Data(generateId(), name)]);}};返回 (<div className="应用程序行">{data.map((li, index) => (<div className="col-4 col-sm-4 col-md-3 col-lg-3 col-xl-3";键={索引}>

setactive_menu(index)}><div className="dashboard_name col-10 col-sm-10 col-md-9 col-lg-10 col-xl-10">{li.name}

))}{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) => (

))}

<RightBar Create_element={Create_element}/>

);}

I am working with react hooks, And encounter a problem where I have been stuck now.

I have one json data which I am getting whenever user logs in so by that I am creating one top bar which shows user names and when user click on those names I am showing some data which they have created or present for them in db, That data I am already getting in data

MY data I am getting from server

 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"
      }
    ]
  }
]

I have one button on side on which I want to create new div, inside the name I have selected from top.

SO suppose I have listed the topbar and there are total of 3 data i.e 3 names, so if data length is smaller than 4 what I am doing, showing a plus button to create one more tab, so user can create one more tab and then they can create one div inside there each tab,

What I have done

I am populating the top bar as well as when I click on side button I am creating one div inside that selected tab.

Issues I am facing

I am linking my code sand box here so it will be easy to understand what I have done and what I am trying to do

Code sandbox

Here in code sand box I have written all my code please check it out.

I have explained every thing what I a m trying to do, I know how to code but not getting any idea or approach.

if there is no data for user then I will start creating tabs and nested elements from 1 for that user.

in each there will be a save button for each new element created, so I will do that, my only consern is to not to loss data on ui when I go one tab to other once I created them

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>
  );
}

解决方案

Issues You are Facing

  1. If length of data is less than four I am providing a plus button to create on more tab (give it default name), but I am not getting any idea how can I create the new one.

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)]);
  }
};

  1. When I click on side button to create one dive inside tab, and I go to other tab and come back again I want that created 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))
  }
};

  1. Suppose I have 3 tabs (data) so when page loads the first tab data I want to show, but it is not showing up I need to click there only it is showing up.

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) => (...

  1. If the data is null then I can create up to 4 tabs this also I a=want some Idea to do it.

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://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>
  );
}

这篇关于如何在全局选项卡中创建动态元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆