Бесконечный цикл с вложенным объектом - PullRequest
0 голосов
/ 14 мая 2019

Зачем это циклично, если я использую {data: {}}, когда все в порядке с {data: 1}?

Пример кодов и ящиков .

import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {
  const [test, setTest] = useState(true);

  const role = useRole({ data: {} }); // with object { data: 1 } all fine

  useEffect(() => {
    setTest(false);
  }, []);

  return 1;
}

export function useRole({ data }) {
  const [role, roleSet] = useState(false);

  useEffect(() => {
    console.log("looping");
    roleSet({});
  }, [data]);

  return role;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Ответы [ 2 ]

1 голос
/ 14 мая 2019

Я думаю, что @TvG сказал прямо на месте. Сравнение объектов осуществляется по ссылкам. Когда вы создаете объект так, как вы это делали в коде, каждый раз будет создаваться новый ссылочный объект.

const role = useRole({ data: {} });

Даже если вы делаете это так:

let defaultRole = { data: {} }
const role = useRole(defaultRole);

Он будет каждый раз создавать новый объект. значение defaultRole будет пересчитываться при каждом рендере.

Что можно сделать здесь, так это то, что React предоставляет нам метод useRef, который не будет изменяться при повторном отображении, если он не был изменен явно. Вот ссылка для чтения:

useRef docs Вы можете сделать что-то вроде этого:

const { useEffect, useState, useRef }  = React


function App() {
  const [test, setTest] = useState(true);
  console.log("running this")
  let baseObj = {
    data: {}
  }
  const roleDefaultValueRef = useRef(baseObj)
  const role = useRole(roleDefaultValueRef.current);
  useEffect(() => {
    setTest(false);
  }, []);

  return 1
}

function useRole({ data }) {
  const [role, roleSet] = useState(false);

  useEffect(() => {
    console.log("looping");
    roleSet({});
    debugger
  }, [data]);

  return role;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Сверните вопрос, почему в этом случае будет работать объект типа data = {}. Так что ваше useRole имеет эффект, который зависит от данных. Допустим, вы назвали useRole как useRole ({})

теперь в вашем useRole вы распространяете значение данных из этого переданного объекта {} так что эта строка

export function useRole({ data }) {

// data will be evaluated as undefined and undefined will remain same on //consecutive rerenders and hence the effect will not run 
}

Это причина, по которой он работает, когда вы передаете пустой объект useRole.

Надеюсь, это поможет. Для понимания попробуйте распечатать значение данных в useRole, вы обязательно поймете это:)

1 === 1 //true
undefined === undefined //true
{} === {} // false
1 голос
/ 14 мая 2019

Я предполагаю, что это связано с тем, как работает javascript.

В реакции useEffect запускается после каждого рендеринга по умолчанию.Способом настройки такого поведения является предоставление списка в качестве второго параметра.

Таким образом, реакция будет проверять после рендеринга на предоставленные значения из предыдущего рендера и вызывать эффект только тогда, когда значения изменились.

Здесь возникает проблема, которую вы можете проверить с помощью приведенного ниже примера:

if(1 === 1) {
    console.log("1 === 1");
}

if({} === {}) {
    console.log("{} === {}");
}

Если вы запустите это, вы можете заметить, что здесь выводится только 1 === 1.Это потому, что javascript не рассматривает два пустых объекта как равные.

Поскольку вы предоставляете { data: {} } и распаковываете значение данных в вашем useRole, в вашем списке есть пустой объект.

Надеюсь, это поможет.

...