Zareagować onClick i zapobiecDefault () odsyłacz odświeżyć / przekierować?

87

Renderuję link z React:

render: ->
  `<a className="upvotes" onClick={this.upvote}>upvote</a>`

Następnie powyżej mam funkcję upvote:

upvote: ->
  // do stuff (ajax)

Przed linkiem miałem w tym miejscu, ale muszę przełączyć się na link i tu jest problem - za każdym razem, gdy klikam na .upvotesstronę, zostaje odświeżona, co próbowałem do tej pory:

event.preventDefault () - nie działa.

upvote: (e) ->
  e.preventDefault()
  // do stuff (ajax)

event.stopPropagation () - nie działa.

upvote: (e) ->
  e.stopPropagation()
  // do stuff (ajax)

return false - nie działa.

upvote: (e) ->
  // do stuff (ajax)
  return false

Próbowałem też wszystkich powyższych rozwiązań używając jQuery w moim index.html, ale wydaje się, że nic nie działa. Co mam tutaj zrobić i co robię źle? Sprawdziłem event.type i clickmyślę, że powinienem jakoś uniknąć przekierowań?

Przepraszam, jestem debiutantem, jeśli chodzi o React.

Dziękuję Ci!

Wordpressor
źródło
1
czy próbujesz użyć składni es2015 dla funkcji?
erichardson
Jakie komponenty tworzysz? Bezpaństwowcy? createClass?
markthethomas
Czy możesz potwierdzić, że onClick faktycznie trafia upvote? Może to być kwestia kontekstu.
thangngoc89
1
UżyjpreventDefault
onmyway133
1
Tylko e.PreventDefault () działało dla mnie (React 16.0.0-beta5)
felix-b

Odpowiedzi:

70

Zdarzenia reakcji to w rzeczywistości zdarzenia syntetyczne, a nie zdarzenia natywne. Jak napisano tutaj :

Delegowanie zdarzeń: React w rzeczywistości nie dołącza programów obsługi zdarzeń do samych węzłów. Po uruchomieniu React zaczyna nasłuchiwać wszystkich zdarzeń na najwyższym poziomie, używając jednego nasłuchiwania zdarzeń. Gdy komponent jest montowany lub odmontowywany, programy obsługi zdarzeń są po prostu dodawane lub usuwane z wewnętrznego mapowania. Gdy wystąpi zdarzenie, React wie, jak je wywołać za pomocą tego mapowania. Gdy w mapowaniu nie ma żadnych programów obsługi zdarzeń, programy obsługi zdarzeń Reacta są prostymi operacjami bez operacji.

Spróbuj użyć Użyj Event.stopImmediatePropagation:

upvote: (e) ->
  e.stopPropagation();
  e.nativeEvent.stopImmediatePropagation();
Alexandr Lazarev
źródło
74

Pełna wersja rozwiązania będzie zawierała metodę upvotes wewnątrz onClick, przekazywała e i używała natywnej e.preventDefault ();

upvotes = (e, arg1, arg2, arg3 ) => {
    e.preventDefault();
    //do something...
}

render(){
    return (<a type="simpleQuery" onClick={ e => this.upvotes(e, arg1, arg2, arg3) }>
      upvote
    </a>);
{
rzymski
źródło
Czy istnieje różnica między e.preventDefault (); będąc na początku czy na końcu funkcji? Gdzie bardziej sensowne jest umieszczenie?
Sartheris Stormhammer
Myślę, że lepiej użyć go na początku
Roman
To złe praktyki, przeczytaj o funkcjach strzałek i .bind(this)kontekście bin w aplikacji reagującej. Na przykład: medium.freecodecamp.org/…
Joyful
z wyjątkiem tego, że jest to po prostu tworzenie funkcji przekazującej argument. Jeśli używasz już reagowania i ES6, nie potrzebujesz funkcji zakresu. Możesz to równie łatwo osiągnąć, wiążąc go z tym w konstruktorze.
Iwnnay
Uważaj, jeśli wyzwolisz renderowanie (np. Zmieniając stan) przed wywołaniem e.preventDefault (), nie przyniesie to żadnego efektu. Więc lepiej mieć to jako pierwszą instrukcję obsługi zdarzeń.
Thim Anneessens
16

spróbuj bind (this), aby twój kod wyglądał jak poniżej -

 <a className="upvotes" onClick={this.upvote.bind(this)}>upvote</a>

lub jeśli piszesz w konstruktorze es6, możesz to zrobić

constructor(props){
   super(props);
   this.upvote = this.upvote.bind(this);
}

upvote(e){   // function upvote
   e.preventDefault();
   return false

}
deepak prakash
źródło
9
To nie ma znaczenia. Otrzymujesz pozytywne głosy, ponieważ ludzie mają thisw swoim programie obsługi zdarzeń i mają zupełnie inny problem.
Dimitar Nestorov
8

render: -> <a className="upvotes" onClick={(e) => {this.upvote(e); }}>upvote</a>

xjinjin
źródło
1
To złe praktyki, przeczytaj o funkcjach strzałek i .bind(this)kontekście bin w aplikacji reagującej. Na przykład: medium.freecodecamp.org/…
Joyful
createReactClass lub Autobinding lub użyj pakietu npm 'auto-bind'
xjinjin Kwietnia
7

W takim kontekście

function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

Jak widzisz, musisz jawnie wywołać funkcję PreventDefault (). Myślę, że ten dokument mógłby być pomocny.

Fabien Sartori
źródło
2

Miłą i prostą opcją, która działała dla mnie, było:

<a href="javascript: false" onClick={this.handlerName}>Click Me</a>
David
źródło
to jest bardzo niedoceniane. Chcę cię pocałować, jeśli nie masz nic przeciwko. uratowałeś mnie od wielu rzeczy, sir. ponieważ element formularza action="javascript: false"również działa.
OzgurBagci
1
@OzgurBagci Użycie powyższej metody spowoduje wyświetlenie ostrzeżeń w Reakcie w nowszych wersjach. Może teraz działać, ale prawdopodobnie nie będzie działać w dłuższej perspektywie. Prawdopodobnie najlepiej jest znaleźć alternatywną metodę, zwłaszcza jeśli używasz bardziej aktualnej wersji React.
David,
1

Dzieje się tak, ponieważ te programy obsługi nie zachowują zakresu. Z dokumentacji reagowania : dokumentacja reagowania

Sprawdź sekcję „brak automatycznego wiązania”. Powinieneś napisać procedurę obsługi w następujący sposób: onClick = () => {}

Wiktor
źródło
1

Gist, który znalazłem i działa dla mnie:

const DummyLink = ({onClick, children, props}) => (
    <a href="#" onClick={evt => {
        evt.preventDefault();
        onClick && onClick();
    }} {...props}>
        {children}
    </a>
);

Kredyt dla srph https://gist.github.com/srph/020b5c02dd489f30bfc59138b7c39b53

TheFullResolution
źródło
1
Czy mogę zasugerować, aby nie używać onClickjako przekazanej nazwy funkcji właściwości, ale handleClickzamiast tego? To mylące, inni mniej doświadczeni programiści mogą pomyśleć, że jest to rzeczywiste zdarzenie dołączone do komponentu, a tak nie jest. Poza tym tworzysz nową funkcję za każdym razem, gdy komponent jest ponownie renderowany, nawet jeśli otrzymuje te same właściwości. Uważa się to za złą praktykę.
elQueFaltaba
0

Jeśli używasz pola wyboru

<input 
    type='checkbox'
    onChange={this.checkboxHandler}
/>

StopPropagation i stopImmediatePropagation nie będą działać.

Ponieważ musisz użyć onClick = {this.checkboxHandler}

rzymski
źródło
0

Jeśli używasz React Router, proponuję zajrzeć do biblioteki React-router-bootstrap, która zawiera przydatny komponent LinkContainer. Ten komponent zapobiega przeładowaniu strony domyślnej, więc nie musisz zajmować się zdarzeniem.

W twoim przypadku może to wyglądać mniej więcej tak:

import { LinkContainer } from 'react-router-bootstrap';

<LinkContainer to={givePathHere}>
    <span className="upvotes" onClick={this.upvote}>upvote</span>
</LinkContainer>
iggirex
źródło
0

Miałem kłopoty z tagami kotwicy iw preventDefaultprzeszłości i zawsze zapominam, co robię źle, więc oto, co odkryłem.

Często mam problem z tym, że próbuję uzyskać dostęp do atrybutów komponentu poprzez ich bezpośrednią destrukcję, tak jak w przypadku innych komponentów React. To nie zadziała, strona załaduje się ponownie , nawet gdy e.preventDefault():

function (e, { href }) {
  e.preventDefault();
  // Do something with href
}
...
<a href="/foobar" onClick={clickHndl}>Go to Foobar</a>

Wygląda na to, że destrukturyzacja powoduje błąd ( Cannot read property 'href' of undefined), który nie jest wyświetlany na konsoli, prawdopodobnie z powodu całkowitego przeładowania strony. Ponieważ funkcja zawiera błąd, funkcja preventDefaultnie jest wywoływana. Jeśli href to #, błąd jest wyświetlany poprawnie, ponieważ nie ma faktycznego ponownego ładowania.

Rozumiem teraz, że mogę uzyskać dostęp do atrybutów tylko jako drugi argument obsługi w niestandardowych komponentach React, a nie do natywnych tagów HTML . Oczywiście, aby uzyskać dostęp do atrybutu znacznika HTML w zdarzeniu, można by to zrobić w następujący sposób:

function (e) {
  e.preventDefault();
  const { href } = e.target;
  // Do something with href
}
...
<a href="/foobar" onClick={clickHndl}>Go to Foobar</a>

Mam nadzieję, że pomoże to innym ludziom, takim jak ja, zdziwić się niewyświetlanymi błędami!

DSav
źródło
0

Nie znalazłem żadnej z wymienionych opcji, które są poprawne lub działają dla mnie, kiedy wszedłem na tę stronę. Dali mi pomysły na przetestowanie różnych rzeczy i stwierdziłem, że to działa.

dontGoToLink(e) {
  e.preventDefault();
 }

render() {
  return (<a href="test.com" onClick={this.dontGoToLink} />});
}
Iwnnay
źródło
0

tak jak czysty js do Preventdefault: w klasie powinieneś tak stworzyć metodę obsługi:

handler(event) {
    event.preventDefault();
    console.log(event);
}
kiarash shamaii
źródło
-1

żadna z tych metod nie działała dla mnie, więc rozwiązałem to za pomocą CSS:

.upvotes:before {
   content:"";
   float: left;
   width: 100%;
   height: 100%;
   position: absolute;
   left: 0;
   top: 0;
}
Suat Ağgez
źródło