Как я могу глубоко клонировать объект, который имеет реагирующий элемент - PullRequest
2 голосов
/ 29 января 2020

Глубокое клонирование объекта, у которого есть реагирующий элемент, сломает этот элемент, и вы больше не можете визуализировать этот элемент,
Вот пример, показывающий эту проблему

import React from "react";
import "./styles.css";

import Demo from "./Demo";

export default function App() {
  const test = <div>I'm a react element</div>;
  console.log("test", test);

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <Demo obj={{ element: test }} />
    </div>
  );
}

//Demo.js

import React from "react";
// import cloneDeep from "lodash.clonedeep";
import CloneDeep from "clone-deep";

const Demo = ({ obj }) => {
  const newProps = CloneDeep(obj);
  console.log(newProps.element);
  // console.log("Demo element", newProps.element);
  return (
    <div>
      I'm Demo Component
      {newProps.element}
    </div>
  );
};

export default Demo;

Я также попробовал пару других библиотек глубокого клонирования, но ни одна из них, похоже, не работает в моем случае !, так вы знаете библиотеку, которая делает это? или, может быть, я могу исправить текущую библиотеку клонирования, делая что-то? или, может быть, я могу написать собственное глубокое клонирование, любой совет по этому поводу?
Что я пробовал до сих пор:
1- Использование import CloneDeep from "clone-deep";, которое приведет к ошибке objects are not valid as a react child
2-Использование import cloneDeep from "lodash.clonedeep"; которая не имеет той же ошибки, что и предыдущая библиотека, но выдает infinity loop, Max Stack ошибку!
Спасибо.

1 Ответ

1 голос
/ 29 января 2020

Я пошел к github clone-deep скопировал их код и сделал пару изменений
1-Сначала я проверяю, является ли значение элементом реагирования, используя React.isValidElement
2-Благодаря @warmachine i используйте React.cloneElement, если объект является реагирующим элементом для клонирования объекта, и если это не так, я делаю то, что всегда делала библиотека

Здесь вы можете увидеть полный код:

import React from "react";
const clone = require("shallow-clone");
const typeOf = require("kind-of");
const isPlainObject = require("is-plain-object");

export function cloneDeep(val, instanceClone) {
  if (React.isValidElement(val)) {
    return React.cloneElement(val);
  } else {
    const valueType = typeOf(val);
    switch (valueType) {
      case "object":
        return cloneObjectDeep(val, instanceClone);
      case "array":
        return cloneArrayDeep(val, instanceClone);
      default: {
        return clone(val);
      }
    }
  }
}

function cloneObjectDeep(val, instanceClone) {
  if (typeof instanceClone === "function") {
    return instanceClone(val);
  }
  if (instanceClone || isPlainObject(val)) {
    const res = new val.constructor();
    for (let key in val) {
      res[key] = cloneDeep(val[key], instanceClone);
    }
    return res;
  }
  return val;
}

function cloneArrayDeep(val, instanceClone) {
  const res = new val.constructor(val.length);
  for (let i = 0; i < val.length; i++) {
    res[i] = cloneDeep(val[i], instanceClone);
  }
  return res;
}

Это, конечно, временное решение, пока я не найду лучшего или, надеюсь, владелец хаба git расскажет о проблеме, которую я разместил

...