Я настраивал веб-сайт / приложение React, используя ранее использованный шаблон, в который интегрирована база данных Redux и Firebase. Однако я использую React Hooks в проекте, использующем этот шаблон впервые. Пока у меня нет проблем с получением данных из Firebase RT-DB и использованием их с useState и useEffect. Теперь я хочу реорганизовать свой код, чтобы сохранить состояние моего приложения в Redux, но по-прежнему использовать функциональные компоненты и также использовать хуки.

У меня проблемы со всем этим.

Моя установка в настоящее время выглядит так ... Я не аутентифицирую какие-либо данные из Firebase, просто загружаю данные напрямую. В качестве примера я включил компонент моей домашней страницы, который имеет 2 основных элемента состояния / данных из Firebase db {firstName } & {фамилия}.

Чтобы прояснить мою проблему, у меня возникли проблемы с получением данных из базы данных в реальном времени внутри генератора действий, а затем с отправкой их в функцию редуктора.

Я включил то, как, по моему мнению, должно выглядеть действие, но я не уверен, правильно ли это и как должна выглядеть функция редуктора.

Любая помощь приветствуется.

app.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { store } from './store/configureStore';
import AppRouter, { history } from './routers/AppRouter';

// const store = configureStore();

const jsx = (
  <Provider store={store}>
    <AppRouter history={history} />
  </Provider>

);

ReactDOM.render(jsx, document.getElementById('app')); 

< Сильный > configureStore.js

import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';

export const reducers = combineReducers({

});

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

// store.js

export function configureStore(initialState = {}) {

  const store = createStore(reducers, initialState, composeEnhancers(applyMiddleware(thunk)), window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());

  return store;
}

export const store = configureStore();

Пример компонента homepage.js

import React, { useState, useEffect } from "react";
import database from '../firebase/firebase';

const HomePage = () => {

    const [firstName, setFirstName] = useState(firstName);
    const [lastName, setLastName] = useState(lastName);

    useEffect(() => {
        database.ref()
            .once('value')
            .then((snapshot) => {
                const data = snapshot.val();
                const { firstName, lastName } = data
                setFirstName(firstName)
                setLastName(lastName)
            })
            .catch((e) => {
                console.log('Error fetching data', e);
            });
    }, []);

    return (
         <div className="homepage-section__content">
            <HomePageTitle firstName={firstName} lastName={lastName} />
         </div>
    )
}

export { HomePage as default };

Компонент homePageTitle.js

import React from 'react';

const HomePageTitle = (props) => (
    <React.Fragment>
        <h1>
            {props.firstName}
            <span>{props.lastName}</span>
        </h1>
    </React.Fragment>
);

export { HomePageTitle as default };

1
i-am-niall 15 Фев 2021 в 22:06

1 ответ

Лучший ответ

Ниже приведен способ переноса состояния локального компонента и обратного вызова useEffect в состояние и действия redux.

Вы можете определить набор действий по запуску, успешному и неудачному извлечению данных.

const setDataLoading = loading => ({
  type: "FETCH_DATA_LOADING",
  payload: loading,
});

const fetchDataSuccess = payload => ({
  type: "FETCH_DATA_SUCCESS",
  payload, // { firstName, lastName }
});

const fetchDataFailure = () => ({ type: "FETCH_DATA_FAILURE" });

const fetchData = () => dispatch => {
  dispatch(setDataLoading(true)); // <-- start loading
  return database.ref() // <-- return Promise chain
    .once('value')
    .then((snapshot) => {
      const { firstName, lastName } = snapshot.val();
      dispatch(fetchDataSuccess({ firstName, lastName }));
    })
    .catch((e) => {
      console.error('Error fetching data', e);
      dispatch(fetchDataFailure());
    })
    .finally(() => dispatch(setDataLoading(false))); // <-- complete loading
};

Определите свой редуктор. Действие FETCH_DATA запускает асинхронное действие для выборки данных, очищает любое текущее состояние ошибки и устанавливает для loading значение true. В случае успеха или неудачи состояние загрузки очищается, и либо данные имени сохраняются, либо устанавливается значение ошибки.

const initialState = {
  error: false,
  loading: false,
  firstName: null,
  lastName: null,
};

const reducer = (state = initialState, action) => {
  switch(action.type) {
    case "FETCH_DATA_LOADING":
      return {
        ...state,
        loading: action.payload,
      };

    case "FETCH_DATA_SUCCESS":
      return {
        ...state,
        error: false,
        ...action.payload, // ...{ firstName, lastName }
      };

    case "FETCH_DATA_FAILURE":
      return {
        ...state,
        error: true,
      };

    default:
      return state;
  }
};

Добавить редуктор в магазин.

import userReducer from './path/to/reducer/above';

const reducers = combineReducers({
  user: userReducer,
});

Подключите HomePage к магазину redux.

const HomePage = () => {
  const dispatch = useDispatch();
  const { error, firstName, lastName, loading } = useSelector(state => state.user);

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

  return (
    <div className="homepage-section__content">
      {error && <div>Error fetching user name</div>}
      {loading ? (
        <LoadingSpinner />
      ) : (
        <HomePageTitle firstName={firstName} lastName={lastName} />
      )}
    </div>
  )
};
1
Drew Reese 16 Фев 2021 в 22:24