Сделайте React Redux Firebase асинхронным

Всем привет !

У меня проблемы с 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 ? теперь мой вопрос.

Спасибо, что прочитали этот текст, и спасибо за вашу помощь.

:)

Я не уверен, как структурировано ваше приложение, но я считаю, что лучшее место для размещения кода firebase будет внутри ваших действий (исходя из моего личного опыта). Так, например, если вашему компоненту необходимо получить данные из firebase при его монтировании, добавьте вызов действия в методе componentDidMount и в действии выполните выборку в firebase, добавив полученные данные в ваше хранилище redux. Затем подключите свой компонент к хранилищу, чтобы получить доступ к данным. Я мог бы быть более полезным, если бы вы подробно рассказали о своем приложении и о том, что вы пробовали до сих пор.

Guilherme Lemmi 01.05.2018 22:11

Привет, @GuilhermeLemmi! Именно этим я и занимаюсь, добавляя больше деталей. Надеюсь, вы могли бы помочь больше. :-)

Selast Lambou 01.05.2018 23:22
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
2
222
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я считаю, что 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! Я использовал второй метод, и он очень хорошо сработал !!!

Selast Lambou 02.05.2018 20:06

Проблема здесь в том, что функция 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
      });
    });
  });
}

спасибо за быстрый ответ! Но я не очень хорошо отвечаю. Это хорошая идея, чтобы слушатель оставался в возвращаемом обещании?

Selast Lambou 02.05.2018 20:09

Да, это. Таким образом, среда выполнения js на самом деле не будет ждать завершения работы слушателя. Вместо этого он зарегистрирует обратный вызов, который вызывается всякий раз, когда приходит ответ от слушателя. Мы управляем всем асинхронным материалом, используя обратные вызовы в JS, поскольку у нас нет концепции потоковой передачи.

Rahul Gaba 03.05.2018 06:30

Хорошо, большое спасибо за вашу помощь. Я подумаю о предложении We manage all the async stuff using callbacks in JS since we don’t have threading concept. Поскольку я делал java и гиперпоточность, но не так :)

Selast Lambou 03.05.2018 18:42

Другие вопросы по теме