#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. Это работает отлично, и объяснение потрясающее!