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!


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();

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>);
{

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

}

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


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.


2

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

<a href="javascript: false" onClick={this.handlerName}>Click Me</a>

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 = () => {}


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


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}


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>

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!


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} />});
}

0

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

handler(event) {
    event.preventDefault();
    console.log(event);
}

-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;
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.