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

Odpowiedz Nowy wątek
2019-07-14 21:30
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, 2019-07-14 21:31

Pozostało 580 znaków

2019-07-15 23:33
0

W JSX funkcje wołasz tak

<g onMouseDown={this.onDown}>

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


Wiedza to potęga
edytowany 1x, ostatnio: Haskell, 2019-07-15 23:35

Pozostało 580 znaków

2019-07-16 18:24
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, 2019-07-16 18:25

Pozostało 580 znaków

2019-07-17 18:58

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:

// 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
// 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, 2019-07-17 20:04

Pozostało 580 znaków

2019-07-18 18:40
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 :)

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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

Robot: CCBot