Łączenie zdarzeń - react, javascript, onMouseDown & onMouseEnter

Łączenie zdarzeń - react, javascript, onMouseDown & onMouseEnter
K9
  • Rejestracja:około 6 lat
  • Ostatnio:prawie 4 lata
  • Postów:23
0

Cześć,

Mam taki problem: potrzebuję "powiązać" ze sobą zdarzenia. Tj. Mamy np. 16 divów ułożonych w szachownicę, chciałbym wywołać jakieś zdarzenie na wybranych divach w następujący sposób:

  1. Najeżdżamy na dowolnego diva myszką
  2. Robimy mouse down, event się uruchamia
  3. Najeżdżamy myszką na kolejne wybrane divy i na każdym z nich po mouse enter event się uruchamia. UWAGA: event mouse enter uruchamia się tylko, gdy jest wciśnięty przycisk myszki
  4. Puszczamy przycisk myszki - event nie może się już wykonać, dopóki ponownie nie zrobimy mouse down, nie wciśniemy przycisku.

Podejrzewam, że brakuje mi odpowiedniego słownictwa, bo niestety nie udało mi się znaleźć w googlach, jak nazywa się tego typu łączenie zdarzeń. Podpowie ktoś? Czy to w ogóle jest wykonalne poprzez same event listenery? Tak na logikę to chyba musi być wykonalne właśnie przez event listenery :D.

edytowany 1x, ostatnio: Kefir92
Freja Draco
Freja Draco
  • Rejestracja:około 7 lat
  • Ostatnio:ponad 3 lata
  • Postów:3394
2

Oczywiście masz na myśli: mouseover.
Użyj zmiennej globalnej przełączanej przez mousedown mouseup. I wtedy zależnie od jej stanu różnie reaguj na mouseover.


K9
  • Rejestracja:około 6 lat
  • Ostatnio:prawie 4 lata
  • Postów:23
0

Dlaczego mouse over, a nie enter? Jest to aż tak istotne w tym wypadku? Różnica dotyczy tylko dzieci, a tu ich nie ma, więc bez różnicy, tak :)?

I dzięki, rano powalczę z ze zmienną globalną :)

Freja Draco
Freja Draco
A... to jakieś funkcje z Reacta, a to się nie wypowiadam.
LukeJL
  • Rejestracja:około 11 lat
  • Ostatnio:minuta
  • Postów:8423
2

ustawiasz flagę po prostu (jakąś zmienną) w czasie mouseDown np. isDown = true, potem sprawdzasz mouseMove czy flaga jest ustawiona, a w mouseUp wyłączasz flagę.


cerrato
Moderator Kariera
  • Rejestracja:około 7 lat
  • Ostatnio:około godziny
  • Lokalizacja:Poznań
  • Postów:8802
2

@Freja Draco, @LukeJL - sam chciałem też napisać coś ze zmienną pomocniczą/flagą, która będzie ustawiana w chwili kliknięcia, a następnie, przy wchodzeniu kursorem na dane elementy, nastąpi sprawdzenie stanu tej flagi. Ale dałem sobie spokój, bo uznałem, że to prowizorka, zaraz zostanę zjechany, że tak się nie robi, że powinno się jakieś hooki ustawiać itp :D

Widać czasami warto zaufać swojej intuicji/pierwszej myśli ;)


WeiXiao
1 mały if czy kolejna warstwa abstrakcji żeby ludzie z forum się nie śmiali? :D
cerrato
wiesz... ciężko jest czasami znaleźć granicę/kompromis miedzy over engineering a prowizorką/tandetą. Zasada "ważne, że działa" nie zawsze jest optymalnym podejściem.
WeiXiao
To czy jest optymalna wychodzi z czasem i dlatego pisze się MVP, aby zdobyć wiedzę nt. co będzie potrzebne.
cerrato
zgadzam się, ale mi chodziło o coś innego. Czasami przy jakiejś głupocie/drobiazgu, nie ma sensu wyciągać "armat" pisać całej otoczki, tylko się zwyczajnie robi na sztukę (np. zamiast robienia kontrolerów, wrzucasz zmienną globalną, którą sobie w różnych miejscach sprawdzasz). Wiem, nie powinno się... i niech pierwszy rzuci kamieniem ten, kto tak nigdy nie robi ;)
Haskell
  • Rejestracja:prawie 10 lat
  • Ostatnio:12 miesięcy
  • Postów:4700
1
Freja Draco napisał(a):

Oczywiście masz na myśli: mouseover.
Użyj zmiennej globalnej przełączanej przez mousedown mouseup. I wtedy zależnie od jej stanu różnie reaguj na mouseover.

Gdy ostatnio coś takiego robiłem, to zrobiłem to w podobny sposób. Niestety nie znalazłem jeszcze biblioteki JS, która pozwalałby takie rzeczy szybko i łatwo ogarnąć. Kod trzeba pisać samemu i niestety liczyć się z różnicami pomiędzy przeglądarkami np. w niektórych przeglądarkach kolejność wywoływania zdarzeń myszy jest inna i trzeba obsłużyć takie przypadki jeżeli kod ma działać na różnych przeglądarkach.


Zaglądali do kufrów, zaglądali do waliz, nie zajrzeli do d**y - tam miałem socjalizm. Czesław Miłosz
K9
  • Rejestracja:około 6 lat
  • Ostatnio:prawie 4 lata
  • Postów:23
0

Mogę jeszcze prosić o przykład, jak się deklaruje taką zmienną globalną z eventem zależnym od mouseDown?

Domyślam się, że należy to zrobić w komponencie funkcyjnym, ale coś nie wychodzi powiązanie tego.

Freja Draco
Freja Draco
  • Rejestracja:około 7 lat
  • Ostatnio:ponad 3 lata
  • Postów:3394
0

zmienna_globalna = 123;

Bez żadnych var / let przed.


K9
  • Rejestracja:około 6 lat
  • Ostatnio:prawie 4 lata
  • Postów:23
0

Niee, wtedy woła, że jest niezdefiniowana zmienna.

Bardziej chodzi mi o przykład, jak poza JSX stworzyć funkcję, listenera, który będzie w tej zmiennej globalnej zapisywal stan, czy przycisk jest kliknięty, czy nie.

Freja Draco
Freja Draco
  • Rejestracja:około 7 lat
  • Ostatnio:ponad 3 lata
  • Postów:3394
0

Nie znam Reacta i nie kumam problemu, ale w JS wygląda to tak:
https://www.w3schools.com/jsref/event_onmousedown.asp


K9
  • Rejestracja:około 6 lat
  • Ostatnio:prawie 4 lata
  • Postów:23
0

W zwykłym JS to nie miałbym problemu :) tutaj potrzebuję to zrobić w Reacie. I wiązanie funkcji jest inne po prostu. Albo jestem jeszcze trochę głupi :)

Haskell
  • Rejestracja:prawie 10 lat
  • Ostatnio:12 miesięcy
  • Postów:4700
0

W JSX funkcje wołasz tak

Kopiuj
<g onMouseDown={this.onDown}>

W komponencie funkcyjnym ofc this jest zbędne. W funkcji onDown ustaw sobie zmienną.


Zaglądali do kufrów, zaglądali do waliz, nie zajrzeli do d**y - tam miałem socjalizm. Czesław Miłosz
edytowany 1x, ostatnio: Haskell
K9
  • Rejestracja:około 6 lat
  • Ostatnio:prawie 4 lata
  • Postów:23
0

Przepraszam, jeszcze za małą mam wiedzę w tych tematach :).

Z tym g przed onMouseDown chodzi Ci o to, żeby wrzucić to w jakiegoś taga, który mi pasuje? Bo taga g, to ja nie znam :D Gadanie na sucho chyba nie ma sensu, poniżej link do repo. W komponencie bazowym Square wrzuciłem to jak to widzę na ten moment. Oczywiście niestety nie działa dobrze :D

Jakby coś było niejasne, albo bez sensu, to proszę o feedback :) Tutaj to widzę tak, że mamy w stanie właściwość isMouseDown: false. Zdarzenie onMouseDown przełącza go na true, po czym zdarzenie onMouseEnter odpala handleMove, które sprawdza isMouseDown, jak jest true, to odpala this.props.onClick(), które przekazuje wyżej w hierarchii, że się wydarzyło i ma robić co należy.

Widzisz gdzie tutaj to źle zrobiłem? Mogę prosić o radę :)?

Repo

edytowany 1x, ostatnio: Kefir92
Maciej Cąderek
Maciej Cąderek
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 3 lata
  • Lokalizacja:Warszawa
  • Postów:1264
3

Ustaw flagę jako state nadrzędnego kontenera i przekazuj ją (jak i funkcję ją modyfikującą) przez propsy. Nie trzeba żadnych kombinacji - wystarczy podstawowa funkcjonalność Reacta.

Przykład:

Kopiuj
// Container.js

import React from 'react';
import Item from './Item';

class Container extends React.Component {
  constructor () {
    this.state = {
      isMouseDown: false,
    }

    this.toggleMouseDown = this.toggleMouseDown.bind(this)
  }

  toggleMouseDown() {
    this.setState({isMouseDown: !this.state.isMouseDown})
  }

  render() {
    return <div className="container">
      {[1, 2, 3, 4, 5, 6, 7, 8, 9].map((key) => (
        <Item
          key={key}
          toggleMouseDown={this.toggleMouseDown}
          isMouseDown={this.state.isMouseDown}
        />
      ))}
    </div>
  }
}

export default Container
Kopiuj
// Item.js

import React from 'react'

class Item extends React.Component {
  constructor() {
    this.state = {
      selected: false,
    }

    this.select = this.select.bind(this)
    this.selectIfMouseDown = this.selectIfMouseDown.bind(this)
  }

  select() {
    this.setState({ selected: true })
  }

  selectIfMouseDown() {
    if (this.props.isMouseDown) {
      this.select()
    }
  }

  render() {
    return (
      <div
        className={`item ${this.state.selected ? 'selected' : ''}`}
        onMouseDown={() => {
          this.props.toggleMouseDown()
          this.select()
        }}
        onMouseUp={this.props.toggleMouseDown}
        onMouseEnter={this.selectIfMouseDown}
      >
          {this.props.isMouseDown ? 'down': 'up'}
      </div>
    )
  }
}

export default Item

Live demo: https://stackblitz.com/edit/react-mousedown-1


Dla tych co proponują użycie globalnej flagi, jest to złe bo:

  1. Zaśmieca globalny namespace
  2. Jest ciężkie w debugowaniu
  3. Nie jest potrzebne
  4. Nie działa (a przynajmniej nie tak jak by się wydawało)

Ostatni punkt wymaga rozwinięcia:

React by przerenderować komponent musi wiedzieć, że zmiana zaszła. React nie nasłuchuje wszelkich zmian w kontekście JS, funkcję render() komponentu trigeruje tylko zmiana stanu przez setState i zmiana propsów.
Od biedy da się zrobić takim hackiem proste rzeczy, ale nie da się synchronizować stanu pomiędzy komponentami. Poniższy przykład "działa", ale tylko dlatego, że oprócz zmiany zmiennej globalnej jest także zmieniany stan komponentu this.setState({ selected: true }) - zauważ, że pozostałe komponenty "nie widzą" stanu myszy, dopóki na nie nie najedzie (w ogóle cyrk się robi jak dłużej poklikasz - mysz Schrodingera, nie wiesz czy wciśnięta czy nie póki nie spojrzysz na nią):

https://stackblitz.com/edit/react-mousedown-2


PS
@cerrato Miałeś dobre przeczucie, po prostu musiałeś troszkę poczekać aż ktoś to zjedzie :P

edytowany 6x, ostatnio: Maciej Cąderek
K9
  • Rejestracja:około 6 lat
  • Ostatnio:prawie 4 lata
  • Postów:23
0

@Maciej Cąderek: Bardzo Ci dziękuję :). W repo które udostępniłem tak właśnie zacząłem działać z tym stanem, przeoczyłem jedynie to, że komponenty inne faktycznie nie wiedzą o tym co się dzieje w konkretnym wybranym wcześniej (klikniętym) komponencie. Tu leżał mój główny problem. Dzięki jeszcze raz :)

Maciej Cąderek
Maciej Cąderek
Proszę bardzo

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.