Как преобразовать асинхронные данные в mapStateToProps?

#reactjs #redux #react-redux #google-cloud-firestore #react-redux-firebase

#reactjs #сокращение #реагировать-redux #google-облако-firestore #react-redux-firebase

Вопрос:

  • Я использую firestoreConnect () для синхронизации моих данных из firestore с redux.

  • Я получаю массив объектов employee обратно из firestore через state.firestore.ordered

  • сотрудник формируется следующим образом:

     {
      id: 'XtVe567...',
      name: {
        first: 'John',
        last: 'Doe'
      }
    }
      
  • В mapStateToProps мне нужно преобразовать форму этих данных, прежде чем возвращать их и передавать в компонент через props

     function mapStateToProps(state) {
    
      const schedules = state.firestore.ordered.employees
        .map(employee => ({
          id: employee.id,
          name: {
            first: employee.name.first,
            last: employee.name.last
          },
          schedule: [null, null, null, null, null, null, null]
        }));
    
      const rota = {
       id: null,
       date: moment(),
       notes: null,
       events: [null, null, null, null, null, null, null],
       published: null,
       body: schedules
      };
    
      return {rota}
    }
      
  • Это приводит к: TypeError: не удается прочитать свойство ‘map’ из undefined

  • Я знаю, это потому, что выборка данных является асинхронной, и в момент времени, когда я сопоставляю state.firestore.ordered.employees свойство employees === undefined, которое не может быть повторено

Итак, мой вопрос в том, как вы выполняете такого рода преобразование данных с помощью асинхронных данных? Есть ли способ каким-либо образом приостановить выполнение mapStateToProps и дождаться возврата данных ПЕРЕД отображением поверх них?

Заранее спасибо и извините, если этот вопрос непонятен, я публикую его впервые.

Ответ №1:

Чтобы быстро заставить это работать, вы могли бы просто сделать что-то вроде:

 function mapStateToProps(state) {

    const employees = state.firestore.ordered.employees;

    const schedules = employees
        ? employees.map(employee => ({
            id: employee.id,
            name: {
                first: employee.name.first,
                last: employee.name.last
            },
            schedule: [null, null, null, null, null, null, null]
        }))
        : undefined;

    const rota = {
        id: null,
        date: moment(),
        notes: null,
        events: [null, null, null, null, null, null, null],
        published: null,
        body: schedules
    };

    return { rota }
}
  

Затем в вашем компоненте вы можете проверить наличие атрибута schedules объекта rota и, если он все еще не определен, отобразить что-нибудь, указывающее, что данные еще не загружены.

Тем не менее, использование такой сложной логики в mapStateToProps для меня является антипаттером. Вы можете использовать шаблон селектора, чтобы сделать ваш код более организованным.

Ответ №2:

Ваш компонент должен реагировать на изменения в базовых данных. Итак, вы можете отобразить что-то вроде этого:

 getSchedules(emps) {
 return emps.map(employee => <SomeEmployeeRenderingComponent emp={employee} /> );
}
render() {
  return (
   <div>{this.getSchedules(this.props.employees).bind(this)}</div>
  )
}
  

и mapstatetoprops становится:

 function mapStateToProps(state) {

  const rota = {
   id: null,
   date: moment(),
   notes: null,
   events: [null, null, null, null, null, null, null],
   published: null,
   employees: state.firestore.ordered.employees
  };

  return rota
}