Рекурсивная функция в Reactjs Крючки? - PullRequest
1 голос
/ 17 апреля 2020

Я хочу обновить состояние, используя реагирующие зацепки useState();?

Вот пример:

У меня есть глобальное состояние поверх приложения:

const [familyTree, setFamilyTree] = useState([
    {
      fam_id: 1,
      name: "No name",
      attributes: {
        "Key1": "*",
        "Key2": "*",
      },
      children: [
        {
          fam_id: 2,
          name: "No Name2",
          attributes: {
            "Key1": "*",
            "Key2": "*",
          },
        },
      ],
    },
  ]);

У меня есть текущий объект для обновления глобального состояния:

let res = {
          fam_id: 2,
          name: "No Name2",
          attributes: {
            "Key1": "Update this",
            "Key2": "*",
          },
        },

Рекурсивная функция в этом случае помогает мне обновить глобальное состояние с совпадающим идентификатором, но у меня сейчас проблема,

const matchAndUpdate = (updater, target) => {
      if (updater.fam_id === target.fam_id) {
        target.name = updater.name;
        target.attributes = updater.attributes;
      }

      if ("children" in target && Array.isArray(target.children)) {
        target.children.forEach((child) => {
          matchAndUpdate(updater, child);
        });
      }
    };
    familyTree.forEach((g) => {
      matchAndUpdate(res, g);
      setFamilyTree({ ...g }); // here is my try, this works on start, but on secound update i got error about forEach is not a function...
    });

Я не знаю, где обновить состояние на правильном пути?

Спасибо, o /

1 Ответ

2 голосов
/ 17 апреля 2020

Поскольку вы обновляете состояние внутри forEach().

Может быть, вам следует использовать .map и обновить состояние в конце проверочного массива.

Это решение:

const matchAndUpdate = (updater, children) => {
    return children.map(_child => {
      if (updater.fam_id === _child.fam_id) {
        return {
          ...updater,
          children: _child.children && Array.isArray(_child.children) ? matchAndUpdate(updater, _child.children) : null
        };
      } else {
        return {..._child,children: _child.children && Array.isArray(_child.children) ? matchAndUpdate(updater,_child.children) : null};
      }
    });
  };

Это вернет и массив дочерних элементов, поэтому вы начнете с исходного массива:

 const finalFamily = matchAndUpdate({ fam_id: 1, name: "Name" }, familyTree);

finalFamily будет окончательно обновленным массивом.

Вы можете обновите состояние следующим образом:

// Option 1:
setFamilyTree(matchAndUpdate({ fam_id: 1, name: "Name" }, familyTree);

// Option 2:
const newFamilyTree = matchAndUpdate({ fam_id: 1, name: "Name" }, familyTree);
setFamilyTree(newFamily);

--- СЛЕДУЮЩИЙ ВОПРОС-- -

Я понимаю, что вы хотите создать метод для pu sh новых потомков потомков, указанных в id .

Я разработал метод, который поддерживает атрибуты и старые дочерние элементы:

  const addChildrenToChild = (parent,numChildren) => {
    const arrayChildren = [];
    for (let i = 0; i < numChildren; i++) {

      arrayChildren.push({
        fam_id: Math.floor(Math.random() * 100),
        name: "No name",
        attributes: {
        key1:"",
        key2:""
        },

      });
    }

    return {...parent,children:parent.children && Array.isArray(parent.children) ? parent.children.concat(arrayChildren) : arrayChildren }
  }

и обновляет matchAndUpdate для поддержки старых детей

 const matchAndUpdate = (updater, children) => {
    return children.map(_child => {
      if (updater.fam_id === _child.fam_id) {
        return {
          ...updater,
          children: updater.children
          //Filter updater children 
            .filter(_childFiltered =>
              _child.children && Array.isArray(_child.children) ? 
              //check if exists new child in old children
              _child.children.some(
                _childToCheck => _childToCheck.fam_id !== _childFiltered.fam_id
              ) : true
            ) 
            //concat old children and check to update
            .concat(
              _child.children && Array.isArray(_child.children)
                ? matchAndUpdate(updater, _child.children)
                : []
            )
        };
      } else {

        return {
          ..._child,
          children: 
              _child.children && Array.isArray(_child.children)
                ? matchAndUpdate(updater, _child.children)
                : []
        };
      }
    });
  };

А теперь. Вы можете одновременно использовать другой метод для добавления новых дочерних элементов:

// Now we are going to add new children to the first element in familyTree array, and maintains old children if it has.
const newFamilyTree = matchAndUpdate(
    addChildrenToChild(familyTree[0], 10),
    familyTree
  );

setFamilyTree(newFamilyTree);

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...