У меня проблемы с redux
и firebase
. Обязательно ли ставить роутеры в корневые компоненты проектов?
Некоторые из моих очень хорошо работают с этой системой, но не с функциями asynchronous
, в основном с функциями firebase
.
Этот пост в основном о том, как и где разместить firebase.[objects]
, чтобы они всегда читались правильно. Официальная документация не очень ясна и понятна.
Напоминаю Я новичок в firebase.
Я попытался разместить их в функциях цикла реакции (например, componentDidMount()
, ...) с момента некоторого срабатывания после рендеринга, но ничего не вышло.
По сути, я так и сделал:
Service.jsx
function getAll() {
// I had saved some values in the localStorage
const uid = JSON.parse(localStorage.getItem('user')).uid;
// Here the reference to appropriate child in the database
const dbRef = firebase.database().ref().child('events');
// Choosing the user with appropriate's is
const userRef = dbRef.child(uid);
// An array to save fetched values
let answer = [];
// Created a listener
userRef.on('value', snap => {
let rx = snap.val();
for (let item in snap.val()) {
answer.push(rx[ item ]);
}
// Return a promise for the actions
return Promise.resolve({
events: answer
});
});
return Promise.resolve({
events: answer
});
}
Reducer.jsx
export function events(state = { events: [] }, action) {
// --------> Get all
case eventConstants.GET_ALL_REQUEST:
return {
...state,
managingEvent: true,
};
case eventConstants.GET_ALL_SUCCESS:
return {
...state,
events: action.events
};
case eventConstants.GET_ALL_FAILURE:
return state;
default:
return state
}
}
Action.jsx
function getAll() {
return dispatch => {
dispatch(request());
eventService.getAll()
.then(
ans => {
dispatch(success(ans.events));
},
error => {
dispatch(failure(error));
dispatch(alertActions.error(error));
}
);
};
function request() {
return { type: eventConstants.GET_ALL_REQUEST }
}
function success(events) {
return { type: eventConstants.GET_ALL_SUCCESS, events }
}
function failure(error) {
return { type: eventConstants.GET_ALL_FAILURE, error }
}
}
Вот что я сделал. Теперь вот что я пытаюсь сделать: получить данные с помощью store.dispatch(Action.getAll())
, потому что я использую эти данные в компоненте поиска. Я использую их так:
Search
// usual imports here, connect inculed
import React, { Component } from 'react';
import { connect } from 'react-redux';
class SearchPage extends Component {
// So I first used the constructor
constructor(props){
this.props.dispatch(Action.getAll());
}
componentDidMount() {
// Then here... an same for all others methods of react lifecycle
this.props.dispatch(Action.getAll());
}
render() {
// TODO Don't forget the translation
let { translate, events } = this.props;
....
const table = (
<Table hover>
{tableHeader}
<tbody>
{events.map(item =>
<tr key = {item.key}>
<th scope = "row">{item.key}</th>
<td>{item.name}</td>
<td>{item.startDate}</td>
<td>{item.endDate}</td>
</tr>
)}
</tbody>
</Table>
);
...
}
const mapStateToProps = (state) => {
const { events } = state.events;
const translate = getTranslate(state.locale);
return {
events,
translate,
};
}
const connectedPage = connect(mapStateToProps)(SearchPage);
export { connectedPage as SearchPage };
Иногда это работало со штрафом, затем, когда я обновлял базу данных в Интернете, а затем она перерисовывалась, он говорил, что event
был нулевым или неопределенным, что я мог понять из-за перехода в Reducer.js
.
But what should I do now ?
теперь мой вопрос.
Спасибо, что прочитали этот текст, и спасибо за вашу помощь.
:)
Привет, @GuilhermeLemmi! Именно этим я и занимаюсь, добавляя больше деталей. Надеюсь, вы могли бы помочь больше. :-)
Я считаю, что return Promise...
в конце getAll () (вне userRef.on('value'...
) в Services.jsx заставляет функцию getAll возвращать undefined, если выборка событий еще не завершена. Я бы реорганизовал Service.jsx следующим образом (методы Firebase уже возвращают обещания, поэтому вы можете вернуть их напрямую):
function getAll() {
const uid = JSON.parse(localStorage.getItem('user')).uid;
const dbRef = firebase.database().ref().child('events');
const userRef = dbRef.child(uid);
let answer = [];
return userRef.on('value', snap => {
snapshot.forEach((snap) => answer.push(snap.val()));
return {
events: answer
};
});
}
Другой подход, который вы можете попробовать, - создать специальный компонент, который ничего не отображает, будучи ответственным только за подключение прослушивателя firebase к componentDidMount и отсоединение его от componentWillUnmount (что-то вроде кода ниже), и они импортируют этот специальный компонент внутри вашего SearchPage. jsx.
class FirebaseListenToEvents extends Component {
componentDidMount() {
const uid = JSON.parse(localStorage.getItem('user')).uid;
const dbRef = firebase.database().ref().child('events');
this.userRef = dbRef.child(uid);
this.userRef.on('value', (snap) => {
this.props.onUpdateEvent(snap.key, snap.val());
});
}
componentWillUnmount() {
this.userRef.off('value');
}
render() {
return null;
}
}
Я не уверен, какой подход подойдет вам лучше всего, но я надеюсь, что это даст вам некоторое представление о том, как работать с Firebase и React. Этот статья также, кажется, объясняет это лучше, чем я. Если у вас возникнут проблемы, просто спросите меня в комментариях. Удачи!
Большое спасибо @Guilheme Lemmi! Я использовал второй метод, и он очень хорошо сработал !!!
Проблема здесь в том, что функция getAll
внутри службы не будет ждать завершения работы слушателя. Из-за этого в переменной ответа всегда будет []
.
Решение состоит в том, чтобы вернуть new promise instance
, который разрешается только после получения данных от firebase.
Обновлен Service.jsx
function getAll () {
// I had saved some values in the localStorage
const uid = JSON.parse(localStorage.getItem('user')).uid;
// Here the reference to appropriate child in the database
const dbRef = firebase.database().ref().child('events');
// Choosing the user with appropriate's is
const userRef = dbRef.child(uid);
// An array to save fetched values
const answer = [];
return new Promise((resolve) => {
// Created a listener
userRef.on('value', (snap) => {
const rx = snap.val();
for (const item in snap.val()) {
answer.push(rx[item]);
}
// Return a promise for the actions
resolve({
events: answer
});
});
});
}
спасибо за быстрый ответ! Но я не очень хорошо отвечаю. Это хорошая идея, чтобы слушатель оставался в возвращаемом обещании?
Да, это. Таким образом, среда выполнения js на самом деле не будет ждать завершения работы слушателя. Вместо этого он зарегистрирует обратный вызов, который вызывается всякий раз, когда приходит ответ от слушателя. Мы управляем всем асинхронным материалом, используя обратные вызовы в JS, поскольку у нас нет концепции потоковой передачи.
Хорошо, большое спасибо за вашу помощь. Я подумаю о предложении We manage all the async stuff using callbacks in JS since we don’t have threading concept
. Поскольку я делал java и гиперпоточность, но не так :)
Я не уверен, как структурировано ваше приложение, но я считаю, что лучшее место для размещения кода firebase будет внутри ваших действий (исходя из моего личного опыта). Так, например, если вашему компоненту необходимо получить данные из firebase при его монтировании, добавьте вызов действия в методе componentDidMount и в действии выполните выборку в firebase, добавив полученные данные в ваше хранилище redux. Затем подключите свой компонент к хранилищу, чтобы получить доступ к данным. Я мог бы быть более полезным, если бы вы подробно рассказали о своем приложении и о том, что вы пробовали до сих пор.