Poprawna modyfikacja stanu React

0

Cześć.
Mam stan: [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]
Chciałbym wyświetlić to w tabeli 3x3
Po kliknięciu na liczbę chciałbym ją pomnożyć razy 2.
W jaki najlepszy sposób zmodyfikować stan i czy trzeba przekazywać położenie w tabeli np: [1,2]
w propsach czy jest jakiś sposób żeby komponent wywnioskował to samodzielnie :D ?

0

Żeby nie było że nic nie mam oto mój kod.
Wiem że to nie react ale zasada działania podobna.
Na razie każdy element wymnaża całą tabelę przez 2:

import { createElement, render, h, Component } from "preact";
const pure = require("purecss");
import "./style.css";
import { html } from "htm/preact";

class Squere extends Component {
  render(props, state) {
    return html`<div
      class="pure-u-1-${props.szer}"
      style="height: ${100 / props.wys}%"
    >
      <div class="center all-height item" onclick="${props.onDuble}">
        <p>${props.number}</p>
      </div>
    </div>`;
  }
}

class App extends Component {
  state = {
    rows: [
      [1, 2, 3],
      [4, 5, 6],
      [7, 8, 9],
    ],
  };

  dubleIt = () => {
    this.setState({
      rows: [...this.state.rows].map((row) => {
        return row.map((number) => number * 2);
      }),
    });
  };

  render(props, state) {
    return html` <div class="pure-g full item">
      ${state.rows.map((row, rows) => {
        return row.map((number, numberIndex) => {
          return html`<${Squere} szer=${row.length} 
                                  wys=${state.rows.length} 
                                  number=${number}
                                  onDuble=${this.dubleIt}>
                      </${Squere}>`;
        });
      })}
    </div>`;
  }
}

render(
  html`
    <main class='center all-viewport-height'>
        <${App}></${App}>
    </main>       
    `,
  document.body
);

2

Mam trochę gotowe. przekazywanie propsów i wynoszenie w górę. Ale w preact i htm, więc pewnie trochę zbyt egzotycznie.
Z preacta trochę korzystałem, ale z tym htm/preact mam pierwszy raz do czynienia.

Jeśli cały czas ma być to tabela 3x3 to można to zmienić w taki sposób, że pozbywamy się tych zagnieżdżonych tablic z state.rows. Render się trochę upraszcza, bo wystarczy nam teraz tylko jedna pętla, oraz żeby zaktualizować klikniętą wartość musimy przekazać jedynie sam index.

class App extends Component {
  state = {
    rows: [1, 2, 3, 4, 5, 6, 7, 8, 9]
  };

  dubleIt(currentIndex) {
    const rows = [...this.state.rows];
    rows[currentIndex] *= 2;
  
    this.setState({
      rows
    });
  }

  render(props, state) {
    return html` <div class="pure-g full item">
      ${state.rows.map((number, index) => {
        return html`<${Squere}
          key=${index}
          szer=${3}
          wys=${3}
          number=${number}
          onDuble=${() => this.dubleIt(index)}
        >
        </${Squere}>`;
      })}
    </div>`;
  }
}
2

nazwy zmiennych.
Squere, Duble - chodziło ci pewnie o Square i Double?
szer, wys - lepiej po angielsku zrobić width, height

0

Wstawiam działającą wersję z poprawkami:

import { createElement, render, h, Component } from "preact";
const pure = require("purecss");
import "./style.css";
import { html } from "htm/preact";

class Square extends Component {
  render(props, state) {
    return html`<div
      class="pure-u-1-${props.width}"
      style="height: ${100 / props.height}%"
    >
      <div
        class="center all-height item"
        onclick="${() => {
          return props.onDouble(props.x, props.y);
        }}"
      >
        <p>${props.number}</p>
      </div>
    </div>`;
  }
}

class App extends Component {
  state = {
    rows: [
      [1, 2, 3],
      [4, 5, 6],
      [7, 8, 9],
    ],
  };

  DoubleIt = (x, y) => {
    const rows = [...this.state.rows];
    rows[x][y] *= 2;
    this.setState({ rows: rows });
  };

  render(props, state) {
    return html` <div class="pure-g full item">
      ${state.rows.map((row, x) => {
        return row.map((number, y) => {
          return html`<${Square} width=${row.length} 
                                  height=${state.rows.length} 
                                  number=${number}
                                  x=${x}
                                  y=${y}
                                  onDouble=${this.DoubleIt}>
                      </${Square}>`;
        });
      })}
    </div>`;
  }
}

render(
  html`
    <main class='center all-viewport-height'>
        <${App}></${App}>
    </main>       
    `,
  document.body
);

Wielkie dzięki za pomoc.

0
const rows = [...this.state.rows];

to ci robi płytką kopię. Co oznacza, że to:

rows[x][y] *= 2;

modyfikuje ci na żywca wewnętrzne tablice.

Obczaj sobie taki kod w czystym JavaScript:

const rows = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9],
];

const copy = [...rows];

copy[1][1] = 100;

console.log(rows); // [ [ 1, 2, 3 ], [ 4, 100, 6 ], [ 7, 8, 9 ] ]

console.log(rows === copy); // false, bo dokonała się płytka kopia

console.log(rows[1] === copy[1]); // true, bo zagnieżdżone tablice są współdzielone

Ogólnie ludzie sobie różnie z tym radzą, ale zwykle głęboki stan w React to koszmar (chyba, że użyjesz specjalnej biblioteki). Ale w tym przypadku ja bym wypieprzył zagnieżdżenie. Czyli luzem po prostu wrzucił wszystko:

state = {
  rows: [
    1, 2, 3,
    4, 5, 6,
    7, 8, 9,
  ],
};

Tak będzie serio łatwiej, bo masz tylko jedną ciągłą tablicę.

const rows = [...this.state.rows];
rows[y * columnCount + x] *= 2;

gdzie columnCount to będzie w tym wypadku 3, bo masz 3 kolumny.

1 użytkowników online, w tym zalogowanych: 0, gości: 1