Als Requisite übergebenes Array spiegelt keine Änderungen wider
P粉685757239
P粉685757239 2023-09-06 17:37:30
0
2
543

Bei dieser Frage geht es eher darum, mehr darüber zu erfahren, wie React mit Änderungen umgeht und auf sie reagiert, als um die Implementierung, daher lasse ich den Immutable-Props-Apprach ein wenig weiterentwickeln.

Ich versuche, das erste Element eines Arrays abzurufen und es aus dem ursprünglichen Array zu entfernen, das als Requisite an die Komponente übergeben wird:

const ChildComponent = (
  arrayToChange: Array<any>[]
) => {
  const elementFromArray = arrayToChange.shift();
}

Aus der Definition der Methode „shift()“::

Die Methode

shift() entfernt das erste Element aus dem Array und gibt das entfernte Element zurück. Diese Methode ändert die Länge des Arrays.

Obwohl die Variable elementFromArray jetzt die Elemente im Array enthält, ist das Array vollständig, es ist in keiner Weise betroffen und enthält weiterhin alle Elemente.

Aber wie ist das möglich? React sollte Requisiten als Referenz übergeben, daher sollte das ursprüngliche Array betroffen sein. Ich würde es verstehen, wenn React einige Schutzmaßnahmen einführen würde und diese Änderungen nicht im übergeordneten Element widergespiegelt würden. Ich möchte jedoch, dass die Änderungen trotzdem im untergeordneten Element widergespiegelt werden. Ich kann nichts Nützliches finden, um dieses Verhalten zu erklären. Die meisten Ressourcen erwähnen nur unveränderliche Methoden für Requisiten und wie man eine Problemumgehung findet, nicht jedoch den Grund oder die Logik dahinter.

Obwohl die Variable elementFromArray jetzt die Elemente im Array enthält, ist das Array vollständig, es ist in keiner Weise betroffen und enthält weiterhin alle Elemente. Wenn ich jedoch die Push()-Methode verwende, werden die Änderungen widergespiegelt und arrayToChange enthält ein weiteres Element.

Meine Frage ist: Warum reagiert arrayToChange unterschiedlich auf diese Methoden? Wenn „shift()“ den Inhalt nicht ändert, hoffe ich, dass push() dies auch nicht ändert.

P粉685757239
P粉685757239

Antworte allen(2)
P粉182218860

function Parent() {
  const forceUpdate = useForceUpdate();
  const [letters] = React.useState(["a", "b", "c"]);

  return (
    <div className="bg-yellow">
      A: {JSON.stringify(letters)}
      <ChildShowArray array={letters} />
      B: {JSON.stringify(letters)}
      <ChildChangeArray arrayToChange={letters} />
      C: {JSON.stringify(letters)}
      <ChildShowArray array={letters} />
      D: {JSON.stringify(letters)}

      <hr />
      <button type="button" onClick={forceUpdate}>re-render</button>
    </div>
  );
}

function ChildChangeArray({ arrayToChange }) {
  const elementFromArray = arrayToChange.shift();
  
  return (
    <div className="bg-red">
      elementFromArray = {JSON.stringify(elementFromArray)}
    </div>
  );
}

function ChildShowArray({ array }) {
  return (
    <div className="bg-green">
      array = {JSON.stringify(array)}
    </div>
  );
}

// helper hook
function useForceUpdate() {
  const [_state, setState] = React.useState({});
  return React.useCallback(() => { setState({}) }, []);
}

ReactDOM.createRoot(document.querySelector("#root")).render(<Parent />)
.bg-yellow { background: yellow }
.bg-red { background: red }
.bg-green { background: green }
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="root"></div>

如果您将渲染过程视为广度优先算法,则可以解释代码片段中的行为。

JSX 将转换:

<div className="bg-yellow">
  A: {JSON.stringify(letters)}
  <ChildShowArray array={letters} />
  B: {JSON.stringify(letters)}
  <ChildChangeArray arrayToChange={letters} />
  C: {JSON.stringify(letters)}
  <ChildShowArray array={letters} />
  D: {JSON.stringify(letters)}
</div>

进入以下 JavaScript:

React.createElement("div", { className: "bg-yellow" },
  "A: ", JSON.stringify(letters),
  React.createElement(ChildShowArray, { array: letters }),
  "B: ", JSON.stringify(letters),
  React.createElement(ChildChangeArray, { arrayToChange: letters }),
  "C: ", JSON.stringify(letters),
  React.createElement(ChildShowArray, { array: letters }),
  "D: ", JSON.stringify(letters),
)

React.createElement(ChildShowArray, { array: letter }) 创建一个不会立即调用 ChildShowArray 组件的结构。它将创建某种中间结构/对象,仅在渲染器要求它运行时运行。

放置在 {...} (JSX 上下文)中的 JavaScript 直接作为参数传递,因此直接解析。这意味着 Parent 中的所有 {JSON.stringify(letters)} 在子组件中的任何代码运行之前运行。

当构建父结构完成后,渲染器将访问每个中间结构/对象并要求其渲染。这是从上到下完成的,这就是为什么第一个 ChildShowArray 渲染仍然显示完整数组的原因。然后渲染 ChildChangeArray 并删除第一个元素。第二个 ChildShowArray 渲染反映了此更改,并且在没有第一个元素的情况下进行渲染。

请注意,shift() 确实会更改 letters 的内容,但是当调用它时,Parent 的内容已经呈现并且不再变化。此更改确实会影响下一次渲染的Parent(单击代码片段中的“重新渲染”按钮)。它还会影响其下方使用相同数组引用的其他子组件的渲染。

P粉287726308

我不完全确定这个问题是什么,但我在这里冒险猜测一下,所以请在这里发表评论,我会在投票之前进行更改。

我认为你应该在你的子组件中尝试这个:

const [data, setData] = React.useState(arrayToChange);

React.useEffect(() => setData(arrayToChange), [arrayToChange.length]);

然后使用“data”映射到 jsx 中的输出

然后在父组件中,对 arrayToChange 进行移位。您可以将 useEffect 视为一个“观察者”,当数组长度发生变化时它将触发。

Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage