Wykrywanie klikniętego elementu aplikacji (React)

0

Problem wygląda następująco:

Po kliknięciu buttona odpala się funkcja na onClicku. Chcę w tej funkcji taką funckjonalność, że wykrywa jaki element aplikacji zostanie wciśnięty następny.

Przykład:

Uzytkownik klika guzik z napisem "Niebieski". Teraz jeśli następny element jaki kliknie to będzie element o id, załóżmy "niebo" to konsola wypisze "sukces", jeśli będzie jakikolwiek inny to wypisze "porażka".

Próbowałem z jakimś window.onclick bez rezultatów.

Chętnie przyjmę wskazówki w Es6.

0

Po kliknięciu buttona odpala się funkcja na onClicku. Chcę w tej funkcji taką funckjonalność, że wykrywa jaki element aplikacji zostanie wciśnięty następny.

Znaczy chcesz by funkcja przewidywała przyszłość? ;)

Próbowałem z jakimś window.onclick bez rezultatów.

W takie globalne rozwiązania się nie baw, nie grzeb też ręcznie w DOM. Zgodnie ze sztuka powinieneś wspólny stan trzymać w nadrzędnym komponencie (lub storze, ale to pomijam) i przekazywać w dół przez propsy, np tak:

const Palette = ({ setColor, color }) => {
  return (
    <div>
      <button value="red" onClick={setColor}>Red</button>
      <button value="blue" onClick={setColor}>Blue</button>
      <p>Chosen: {color}</p>
    </div>
  )
}

const Items = ({ matchColor }) => {
  return (
    <div>
      <img
        src="https://goo.gl/69pXq3"
        onClick={() => matchColor('blue')}
      />
      <img
        src="https://goo.gl/9xLksh"
        onClick={() => matchColor('red')}
      />
    </div>
  )
}

class App extends React.Component {
  constructor(props) {
    super(props)
    
    this.state = {
      color: 'red',
      result: '---',
    }
    
    this.setColor = this.setColor.bind(this)
    this.matchColor = this.matchColor.bind(this)
  }
  
  setColor({ target }) {
    this.setState({ color: target.value })
  }
  
  matchColor(imageColor) {
    this.setState({ result: imageColor === this.state.color ? 'OK!' : 'WRONG!' })
    setTimeout(() => {
      this.setState({ result: '---' })
    }, 1000)
  }
  
  render() {
    return (
      <div>
        <Palette setColor={this.setColor} color={this.state.color} />
        <Items matchColor={this.matchColor} />
        <p>{this.state.result}</p>
      </div>
    )
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('app')
)

(Kod taki sobie, ale chodzi o ideę)

CodePen: https://codepen.io/caderek/pen/wPyxow?editors=0011

0

Widzę zamysł, ale czuje, że słabo to wygląda, za przykład podałem coś prostego, to co chcę zrobić jest trochę bardziej rozbudowane + dużo takich rzeczy będzie i teraz trzymanie wszystkiego w oddzielnym komponencie to zamiast uprościć zrobi się brzydko mówiąc burdel. Jak robiłem to samo w czystym JS to osiągnąłem ten cel (brzydko, ale zawsze) w kilka linijek, tu powstaje kobyła, w której trzeba rozpatrzeć wszystkie przypadki.

Chyba ograniczę się do takiego myku, że po kliknięciu guzika użytkownik dostanie na kilka sekund, że button.state = true, i w czasie gdy jest true może sobie klikać aż trafi na odpowiednie miejsce na ekranie. Paskudne rozwiązanie do "przygodówki", ale już większość roboty w reactie zrobiłem to nie chcę się teraz wycofać przez taki myk.

0

to co chcę zrobić jest trochę bardziej rozbudowane + dużo takich rzeczy będzie i teraz trzymanie wszystkiego w oddzielnym komponencie to zamiast uprościć zrobi się brzydko mówiąc burdel

E, niekoniecznie, wydaje mi się, że można to zrobić mocno generycznie (zależy jak ta gra ma działać).

Innym pomysłem może być podpięcie Reduksa i na przykład redux-observable - możesz wtedy sobie analizować streamy eventów i mapowac poszczególne sekwencje na konkretne akcje. No ale to jest szybkie i wygodne pod warunkiem, że dobrze ogarniasz Rx'a (więc jeśli jesteś poczatkujący to raczej odpada, choć to mocno rozijające).

0

Z Reduxa korzystam, ale dopiero go zaczynam i chyba nie będę wskakiwał na tak głęboką wodę jak mówisz, że to wygląda groźnie. Już i tak pracuję z prawie 30 plikami a robię dopiero pierwszy poziom i jest on krótki, to się rozrośnie do monstrualnych rozmiarów, zwłaszcza, że napotykam następne problemy i widze, że niektóre style też będe musiał trzymać w storze i zaraz czuję, że się pogubie.

Ten duży projekt już mi w sumie sporo dał i chciałbym go skończyć, ale jak dołożę sobie jeszcze więcej to skończyć się to może różnie.

Prześpię się z problemem, sprobouje rozwiazac inne, jak na nic nie wpadnę to albo zmodyfikuję Twój pomysł albo zerknę na bibliotekę co zaproponowałeś.

Ogólnie ten problem w czystym JS rozwiązałem i widać go tutaj jak ktoś chciałby się pobawić, zajmie mu to pewnie pol minuty:
http://crowstorm.pl/nohome/dead/dead.html

Szukasz przecinaka, przecinak aktywujesz, podswietla sie, jak klikniesz gdy jest aktywny w nieodpowiednie miejsce dezaktywuje się. Ale kod, który powoduje, że to działa to robota frankesteina(dlatego staram sie po pol roku i poznaniu Reacta to przenieść i wprowadzić sensowny kod):

// chain mechanics

var last_clicked = null;
var count=0;
window.onclick = function (e) {
    last_clicked = e.target;

    if(boltcutters_used == true){
    	count++;
    }
    if(boltcutters_used == true && last_clicked !== document.getElementById("chain") && count >1){
		alert("Can't use it here");
		boltcutters_used = false;
		document.getElementById('item_boltcutters').style.color = "white";
		document.getElementById('item_boltcutters').style.border = "1px solid white";
		count=0;
	}
}

var boltcutters_used = false;
document.getElementById('item_boltcutters').onmousedown = function(){
	boltcutters_used = true;
	document.getElementById('item_boltcutters').style.color = "red";
	document.getElementById('item_boltcutters').style.border = "1px solid red";
}

function newPage(){
	location.href = "../freedom/freedom.html";
}

var boltcutters_found = false;
document.getElementById("chain").onmousedown = function(){
	if(boltcutters_used){
		chainBroken.play();
		setTimeout(function() {
    		newPage(); 
			}, 2500);
	} else if(!boltcutters_found){
		alert("I need to find something to break this chain...")
	} else {
		alert("Boltcutters could do the trick")
	}
}

1

To, że powstanie więcej kodu niekoniecznie oznacza że będzie się gorzej kodziło. Może być wręcz odwrotnie. Ja wolałbym mieć 10 etapowe przetwarzanie, gdzie każdy etap byłby mały i wzajemnie od siebie odizolowany niż mieć wszystko nadziubdziane jako pajęczynę zmian w skomplikowanym mutowalnym stanie. Mając 10 małych niezależnych etapów mogę skupić się na każdym z osobna i osobno je też testować.

0

W sumie rozwiązałem chyba problem. Puscilem testową funkcję w komponencie, która trzyma wszystkie podpoziomy danej lokacji i aktywuje się, gdy klikam w button

test2(){
        var click;
        window.onclick = function(e){
            click = e.target;
            if(click.id === 'chainChainedDoor'){
                console.log('dziala')
            }
        }
    }

    test(){
        if(this.props.inventory.activeItem.boltcutters){
            this.test2();
        }
        

Nie wiem jak to z tak zwaną dobrą praktyką, ale kodu mało (dojdzie jeszcze kilka linijek po poprawie, ale to tyle co kot napłakał w porównaniu jakby dodawać store) i działa więc na razie chyba będę zadowolony.

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