Hooki reactowe: dispatch action from useEffect

Moja struktura folderów:

|--App
  |--Components
    |--PageA.js
    |--PageB.js
    |--PageC.js
  |--common-effects
    |--useFetching.js

Refaktoryzuję mój kod do pobierania danych z API, używając reactowych hooków . Chcę wysłać akcję z useEffect w useFetching.js, który jest przechwytywany przez Saga middleware. Akcja powinna być wysłana tylko wtedy, gdy komponenty (PageA, PageB, PageC).

Używam redux, react-redux oraz redux-saga .

PageA.js :

function(props) {
  useFetching(actionParams)
  //....//
}

Podobny kod dla pageb i PageC komponentów.

Pobrałem kod wielokrotnego użytku, aby pobrać dane w useFetching własny hak .

useFetching.js

const useFetching = actionArgs => {
  useEffect( () => {
    store.dispatch(action(actionArgs)); // does not work
  })
}

Nie wiem jak uzyskać dostęp do redux dispatch w useFetching. Próbowałem z efektem useReducer, ale sagi ominęły akcję.

Author: HarshvardhanSharma, 2019-02-28

5 answers

Trzeba by przekazać do haka albo bound Action creators albo referencję do dispatch. Pochodziły one z podłączonego komponentu, tak samo jak normalnie używałbyś Reacta-Redux:

function MyComponent(props) {
    useFetching(props.fetchSomething);

    return <div>Doing some fetching!</div>
}

const mapDispatch = {
    fetchSomething
};

export default connect(null, mapDispatch)(MyComponent);

Hook powinien następnie wywołać związanego kreatora akcji w efekcie, który odpowiednio wyśle akcję.

Należy również pamiętać, że bieżący hook uruchomi efekt Co, gdy komponent zostanie ponownie wyrenderowany, a nie tylko za pierwszym razem. Musisz zmodyfikować hook tak:

const useFetching = someFetchActionCreator => {
  useEffect( () => {
    someFetchActionCreator();
  }, [])
}
 14
Author: markerikson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-28 16:51:40

Wersja wykorzystująca Hooki react-redux:

Możesz nawet całkowicie wyciąć funkcję connect używając useDispatch z react-redux:

export default function MyComponent() {
  useFetching(fetchSomething);

  return <div>Doing some fetching!</div>
}

With your custom hook

import { useDispatch } from 'react-redux';

const useFetching = (someFetchActionCreator) => {
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(someFetchActionCreator());
  }, [])
}

Edit: usunięty z custom hook zgodnie z sugestią @yonga-springfield

Uwaga: React gwarantuje, że tożsamość funkcji dispatch jest stabilna i nie zmieni się przy ponownym renderowaniu. Dlatego można bezpiecznie pominąć listę zależności useEffect lub useCallback.

 37
Author: Alex Hans,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-26 08:52:34

To tylko po to, aby wprowadzić optymalizację do odpowiedzi @ Alex Hans.

Zgodnie z dokumentacją tutaj . Hook Niestandardowy to funkcja JavaScript, której nazwa zaczyna się od "use" i może wywoływać inne Hooki.

Mając to na uwadze, nie musimy wysyłać odwołania do funkcji dispatch do Hooka useFetching jako parametru, ale raczej po prostu nie wysyłać go i używać go z poziomu Hooka useFetching z odpowiednim importem.

Oto fragment co mam na myśli.

import { useDispatch } from 'react-redux';

const useFetching = (someFetchActionCreator) => {
    const dispatch = useDispatch()

    useEffect(() => {
    dispatch(someFetchActionCreator());
  }, [])
}

Nie mogę się upewnić, że ten przykład będzie pasował bez błędów w Twoim kodzie w Twoim przypadku, ale po prostu staram się wyjaśnić ideę / koncepcję stojącą za tym postem.

Mam nadzieję, że to pomoże każdemu przyszłemu przybyszowi.
 7
Author: yonga springfield,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-23 11:44:37

Alex Hans słuszna decyzja z dispatch, ale aby wyeliminować pętle żądania do api można określić zależność od dispatch (użyłem Redux Toolkit)

  import React, { useEffect } from 'react'
  import { useDispatch } from 'react-redux'
  import axios from 'axios'
  import { getItemsStart, getItemsSuccess, getItemsFailure } from '../features/itemsSlice'

  const fetchItems = () => async dispatch => {
    try {
      dispatch(getItemsStart());
      const { data } = await axios.get('url/api')
      dispatch(getItemsSuccess(data))
    } catch (error) {
      dispatch(getItemsFailure(error))
    }
  }

  const PageA = () => {
    const dispatch = useDispatch()
    const { items } = useSelector(state => state.dataSlice)
   
    useEffect(() => {
       dispatch(fetchItems())
    }, [dispatch])

    return (
      <ul>
         {items.map(item => <li>{item.name}</li>}
      </ul> 
    )
  }
  
  export default PageA

Ważne jest podanie parametru zależności dispatch w useEffect (() = > {...}, [dispatch])

 5
Author: FreeClimb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-07-23 10:46:03
useEffect(() => {
   fetchData();
 }, []);

 async function fetchData() {
   try {
     await Auth.currentSession();
     userHasAuthenticated(true);
   } catch (e) {
     if (e !== "No current user") {
       alert(e);
     }
   }
   dispatch(authentication({ type: "SET_AUTHING", payload: false }));
 }
 0
Author: Asgar Ali Khachay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-09 17:34:27