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

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 :)

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ą.

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

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:

// 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

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 :)

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