Рефакторинг кода React, для использования состояния Redux из базы данных Firebase RT и перехватов Redux

#reactjs #firebase #firebase-realtime-database #react-redux #react-hooks

#reactjs #firebase #firebase-realtime-database #react-redux #реагирующие перехваты

Вопрос:

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

У меня возникли проблемы с объединением всего этого.

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

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

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

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

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__ amp;amp; 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. Кажется, вы могли бы использовать стандартные действия для отправки действия для извлечения из БД, использовать thunk для обработки асинхронной логики и отправлять успешное действие для обновления вашего хранилища redux. Что вы уже пробовали? Можете ли вы включить свои действия и редукторы? Есть ли у вас какой-то конкретный аспект или проблема?

2. Я еще ничего не пробовал, так как не уверен, как это сделать. Я знаю, что есть перехваты Redux, useReducer и useSelector, но как я их интегрирую, я не уверен. Это в основном моя проблема. Я думаю, мне нужно переместить выборку базы данных в действие, но как я затем передам ее в редуктор, а затем в хранилище, я не уверен, как это сделать.

3. react-redux имеет useDispatch и useSelector перехваты, useReducer является стандартным перехватом React, не связанным с redux (но применяющим очень похожий шаблон). Если вы уже знакомы с react-redux тем, что отправка действия по сути такая же, как и раньше при использовании «mapDispatchToProps», за исключением того, что теперь это больше не реквизит, и создатели действий точно такие же. Если использование перехватов все еще немного сбивает с толку, вы все равно можете использовать более старый connect компонент более высокого порядка, с которым вы, возможно, более знакомы. Отсюда мы могли бы помочь заставить его работать или преобразовать для использования перехватов.

4. Да, я пытаюсь использовать перехваты. Я впервые извлекаю данные из firebase и внутри Redux, поэтому для меня это совершенно ново. Любая помощь или указания были бы отличными.

Ответ №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 amp;amp; <div>Error fetching user name</div>}
      {loading ? (
        <LoadingSpinner />
      ) : (
        <HomePageTitle firstName={firstName} lastName={lastName} />
      )}
    </div>
  )
};
 

Комментарии:

1. Это работает отлично, и объяснение потрясающее!