React - отображать временную метку пожарного депо

10

Я пытаюсь выяснить, как отобразить метку времени firestore в приложении реагирования.

У меня есть документ пожарного магазина с полем, созданным с именем.

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

componentDidMount() {
    this.setState({ loading: true });

    this.unsubscribe = this.props.firebase
      .users()
      .onSnapshot(snapshot => {
        let users = [];

        snapshot.forEach(doc =>
          users.push({ ...doc.data(), uid: doc.id }),
        );

        this.setState({
          users,
          loading: false,
        });
      });
  }

  componentWillUnmount() {
    this.unsubscribe();
  }

  render() {
    const { users, loading } = this.state;

    return (
        <div>
    {loading && <div>Loading ...</div>}

            {users.map(user => (

                <Paragraph key={user.uid}>  

       <key={user.uid}>  
       {user.email}
       {user.name}
       {user.createdAt.toDate()}
       {user.createdAt.toDate}
       {user.createdAt.toDate()).toDateString()}

Единственный атрибут, который не будет отображаться - это дата.

Каждая из вышеуказанных попыток генерирует ошибку, которая говорит:

TypeError: Невозможно прочитать свойство 'toDate' из неопределенного

Я видел этот пост и этот пост и этот пост и этот пост и иже с ними, которые предполагают , что Todate () должен работать. Но - это расширение выдает ошибку для меня - в том числе, когда я пробую расширение toString.

Я знаю, он знает, что в firestore что-то есть, потому что, когда я пытаюсь использовать user.createdAt, я получаю сообщение об ошибке, в котором говорится, что он нашел объект с секундами в нем.

Взяв пример из Waelmas ниже, я попытался записать вывод поля как:

this.db.collection('users').doc('HnH5TeCU1lUjeTqAYJ34ycjt78w22').get().then(function(doc) {
  console.log(doc.data().createdAt.toDate());

}

Я также попытался добавить это в свой оператор map, но получил ошибку, в которой говорится, что user.get не является функцией.

{user.get().then(function(doc) {
                    console.log(doc.data().createdAt.toDate());}
                  )}

Он генерирует то же сообщение об ошибке, что и выше.

введите описание изображения здесь

СЛЕДУЮЩАЯ ПОПЫТКА

Одна странная вещь, которая возникла при попытке найти способ записи даты в Firestore, которая позволяет мне затем прочитать ее, заключается в том, что когда я меняю свой обработчик отправки в одной форме, чтобы использовать эту формулировку:

handleCreate = (event) => {
    const { form } = this.formRef.props;
    form.validateFields((err, values) => {
      if (err) {
        return;
      };
    const payload = {
    name: values.name,
    // createdAt: this.fieldValue.Timestamp()
    // createdAt: this.props.firebase.fieldValue.serverTimestamp()

    }
    console.log("formvalues", payload);
    // console.log(_firebase.fieldValue.serverTimestamp());


    this.props.firebase
    .doCreateUserWithEmailAndPassword(values.email, values.password)
    .then(authUser => {
    return this.props.firebase.user(authUser.user.uid).set(
        {
          name: values.name,
          email: values.email,
          createdAt: new Date()
          // .toISOString()
          // createdAt: this.props.firebase.fieldValue.serverTimestamp()

        },
        { merge: true },
    );
    // console.log(this.props.firebase.fieldValue.serverTimestamp())
    })
    .then(() => {
      return this.props.firebase.doSendEmailVerification();
      })
    // .then(() => {message.success("Success") })
    .then(() => {
      this.setState({ ...initialValues });
      this.props.history.push(ROUTES.DASHBOARD);

    })


  });
  event.preventDefault();
    };

Это работает, чтобы записать дату в базе данных.

Форма входа в пожарный магазин выглядит так:

введите описание изображения здесь

Я пытаюсь отобразить дату в этом компоненте:

class UserList extends Component {
  constructor(props) {
    super(props);

    this.state = {
      loading: false,
      users: [],
    };
  }

  componentDidMount() {
    this.setState({ loading: true });

    this.unsubscribe = this.props.firebase
      .users()
      .onSnapshot(snapshot => {
        let users = [];

        snapshot.forEach(doc =>
          users.push({ ...doc.data(), uid: doc.id }),
        );

        this.setState({
          users,
          loading: false,
        });
      });
  }

  componentWillUnmount() {
    this.unsubscribe();
  }

  render() {
    const { users, loading } = this.state;

    return (
      <div>
          {loading && <div>Loading ...</div>}

          <List
            itemLayout="horizontal"
            dataSource={users}

            renderItem={item => (
              <List.Item key={item.uid}>
                <List.Item.Meta
                  title={item.name}
                  description={item.organisation}
                />
                  {item.email}
                  {item.createdAt}
                  {item.createdAt.toDate()}
                  {item.createdAt.toDate().toISOString()}

              </List.Item>
            // )
          )}
          />

      </div>
    );
  }
}

export default withFirebase(UserList);

Когда я пытаюсь прочитать это обратно - используя:

{} Item.email

Сообщение об ошибке гласит:

Ошибка: объекты недопустимы как дочерний элемент React (найдено: метка времени (секунд = 1576363035, наносекунд = 52000000)). Если вы хотите отобразить коллекцию дочерних элементов, используйте вместо этого массив. в элементе (в UserIndex.jsx: 74)

Когда я пытаюсь использовать каждую из этих попыток:

{item.createdAt}
{item.createdAt.toDate()}
{item.createdAt.toDate().toISOString()}

Я получаю сообщение об ошибке:

TypeError: Невозможно прочитать свойство 'toDate' из неопределенного

Основываясь на способности читать записи, записанные в том же документе в других полях, я ожидаю, что любое из них сработает, чтобы вывести выходные данные, даже если они не отформатированы так, как я хочу. Этого не происходит.

СЛЕДУЮЩАЯ ПОПЫТКА

Принимая пример Вельмаса, я пытался следовать инструкциям, но там, где мы не получаем тот же ответ, это первый шаг. Когда Walemas получает вывод, основанный на расширении .toDate (), я получаю сообщение о том, что toDate () не является функцией.

В соответствии с документацией Firebase я попытался:

    const docRef = this.props.firebase.db.collection("users").doc("HnH5TeCU1lUjeTqAYJ34ycjt78w22");

docRef.get().then(function(docRef) {
    if (doc.exists) {
        console.log("Document createdAt:", docRef.createdAt.toDate());

}})

Это приводит к ряду ошибок с синтаксисом, и я не могу найти способ их обойти.

СЛЕДУЮЩАЯ ПОПЫТКА

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

У меня есть форма, которая принимает входные данные как:

this.props.firebase.db.collection("insights").add({
            title: title,
            text: text,
            // createdAt1: new Date(),
            createdAt: this.props.firebase.fieldValue.serverTimestamp()
        })

Если в предыдущей форме новая попытка Date () работала для записи даты в базу данных, то в этом примере оба поля для createAt и selectedAt1 генерируют одну и ту же запись базы данных:

введите описание изображения здесь

<div>{item.createdAt.toDate()}</div>
                    <div>{item.createdAt.toDate()}</div>

Когда я пытаюсь вывести значение дат, первое выдает ошибку, которая говорит:

Объекты недопустимы в качестве дочерних элементов React (найдено: вс 15 декабря 2019 21:33:32 GMT + 1100 (по восточному летнему времени Австралии)). Если вы хотите отобразить коллекцию дочерних элементов, используйте вместо этого массив

Второй генерирует ошибку, говоря:

TypeError: Невозможно прочитать свойство 'toDate' из неопределенного

Я застрял на идеи о том, что попробовать дальше.

Я видел этот пост, который предполагает, что следующее может сделать что-то полезное:

                {item.createdAt1.Date.valueOf()}

Это не так. Это делает ошибку, которая говорит:

TypeError: Невозможно прочитать свойство 'Date' из неопределенного

Кажется, у этого поста такая же проблема, как и у меня, но в нем не рассматривается, как им удалось отобразить значение даты, которое они сохранили.

Это сообщение, похоже, застревает в сообщении об ошибке массива, но, похоже, выяснило, как отображать дату с помощью createAt.toDate ()

Мел
источник

Ответы:

1

После некоторого обсуждения мы обнаружили, что метки времени в пользовательском объекте OPs могут отображаться так:

render() { 
const { users, loading } = this.state; 

return ( 
    <div> 
        {loading && <div>Loading ...</div>} 

        {users.map(user => ( 

            <Paragraph key={user.uid}> 

                <key={user.uid}> 
                    {user.email} 
                    {user.name} 
                    {new Date(user.createdAt.seconds * 1000).toLocaleDateString("en-US")}

Я воссоздал ваш пример в фиктивном проекте React и получил ту же ошибку, что и ожидалось.

Ошибка: объекты недопустимы как дочерний элемент React

Я смог заставить это правильно отображаться с помощью следующего метода, который также должен работать для вас:

{new Date(user.createdAt._seconds * 1000).toLocaleDateString("en-US")}

Который, для моей временной метки образца, представлен как:

12/30/2019


Убедитесь, что вы используете метку времени, которая была сохранена в Firestore как:

createdAt: this.props.firebase.Timestamp.fromDate(new Date())

Примечание: это предполагает, что ваш экземпляр firebase.firestore()находится вthis.props.firebase . В других примерах вы используете this.props.firebase, но эти методы выглядят как вспомогательные методы, которые вы создали сами.

Когда это значение выбрано, это будет объект с двумя свойствами - _secondsи _nanoseconds.

Обязательно укажите подчеркивание. Если вы используете createdAt.secondsэто не будет работать, это должно быть createdAt._seconds.


Другие вещи, которые я пробовал:

user.createdAt.toDate()броски toDate() is not a function.

user.createdAt бросает Error: Objects are not valid as a React child

new Date(user.createdAt._nanoseconds) отображает неверную дату

Майкл Родригес
источник
Привет - спасибо за предложение. Я пробовал это и получаю сообщение об ошибке: TypeError: Невозможно прочитать свойство 'Timestamp' из неопределенного
Mel
Я также попытался: createAt: firebase.firestore.fieldValue.serverTimestamp (). FromDate (new Date ()), который возвращает ошибку, которая говорит: TypeError: Невозможно прочитать свойство 'fieldValue' из undefined
Mel
Хотя это не сработало для меня, мне интересно понять, почему вы решили попробовать формат, который вы использовали. Это не так, как показано в документации. Если я смогу узнать, как вы обнаружили что-то, что работает для вас, это может позволить мне найти способ, который работает для меня (я не понимаю, почему это не одно и то же для всех - но мне нужны новые идеи, чтобы попробовать ). Еще раз спасибо за попытку помочь.
Мел
Что я могу сделать, это сохранить дату (как показано выше), используя: createAt: this.props.firebase.fieldValue.serverTimestamp (),
Mel
1
Давайте продолжим эту дискуссию в чате .
Майкл Родригес
5

Когда вы получаете метки времени из Firestore, они имеют следующий тип:

введите описание изображения здесь

Чтобы преобразовать это в обычную метку времени, вы можете использовать функцию .toDate ().

Например, для документа, подобного следующему:

введите описание изображения здесь

Мы можем использовать что-то вроде:

db.collection('[COLLECTION]').doc('[DOCUMENT]').get().then(function(doc) {
  console.log(doc.data().[FIELD].toDate());
});

и вывод будет таким:

2019-12-16T16:27:33.031Z

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

Например: (я использую Node.js здесь)

db.collection('[COLLECTION]').doc('[DOCUMENT]').get().then(function(doc) {
  var stringified = doc.data().[FIELD].toDate().toISOString();
  //console.log(stringified);
  var split1 = stringified.split('T');
  var date = split1[0].replace(/\-/g, ' ');
  console.log(date);
  var time = split1[1].split('.');
  console.log(time[0]);
});

Даст вам вывод, как это:

введите описание изображения здесь

Waelmas
источник
Спасибо за пример. У меня такая же структура в моей попытке. Он работает, чтобы вернуть все строковые значения в документе, но не дату. Вместо этого он генерирует ошибку с сообщением, которое я разместил выше. Это не имеет никакого смысла. Я попытался добавить расширение toISOString (), но оно не меняет сообщение об ошибке (это должно быть только форматирование)
Mel
Можете ли вы записать значение метки времени в консоли? Просто чтобы подтвердить, что это правильный тип метки времени Firestore. @Mel
Waelmas
Нет - журнал консоли не работает - он тоже генерирует ошибку - но дата записывается в поле createAt в таблице - теперь я просто пытаюсь прочитать его обратно. Я создал пост, объясняющий, как я получил дату для записи (не согласно документации Firebase) здесь: stackoverflow.com/questions/59257755/…
Мел
Поскольку вы придерживаетесь другого подхода, чем тот, который рекомендован официальными документами, я не уверен, что на самом деле идет не так. Кажется, что то, как вы создаете и нажимаете временную метку, каким-то образом ошибочно. Когда вы сохраняете метку времени в Firestore, она должна быть объектом того формата, который я упоминал в начале моего ответа. Таким образом, он распознается как допустимая временная метка, которую затем можно использовать с .toDate (). Firestore.Timestamp.now () даст вам метку времени правильного формата, чтобы проверить это. @Mel
Waelmas
Я попытался следовать официальной документации, чтобы создать метку времени. Я не мог заставить его работать. Я наткнулся на альтернативный способ записи даты и теперь не могу прочитать результат! Так расстраивает. В любом случае, спасибо за попытку помочь.
Мел
2

Таким образом, FireStore хранит даты как объект с секундами и наносекундами. Если вы хотите время, когда пользователь был создан, вы бы ссылались user.createdAt.nanoseconds. Это возвращает метку времени Unix.

Как вы хотите отображать дату в вашем приложении? Если вы хотите получить объект даты, вы можете передать метку времени в конструктор даты следующим образом new Date(user.createdAt.nanoseconds). Лично мне нравится использовать библиотеку date-fns для обработки времени.

Джош Питтман
источник
Спасибо - я попробовал это предложение. Он возвращает ошибку, которая говорит: TypeError: Невозможно прочитать свойство «наносекунды» неопределенного. Я посмотрю на библиотеку, которую вы предложили сейчас
Мел
Можете войти в систему и поделиться, пожалуйста. Учитывая асинхронную природу данных, вам, вероятно, просто нужно вернуть их так user.createdAt && new Date(user.createdAt.nanoseconds). Date-fns не поможет с этой проблемой, это просто удобная библиотека для отображения даты, когда она у вас есть.
Джош Питтман
создал в журнале длинный список выпадающих меню. Я не могу найти тот, который содержит дату, указанную в поле в пожарном депо. Первая часть: createdAt: ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" прото : FieldValueImpl конструктор: ƒ ServerTimestampFieldValueImpl () экземпляра: ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" прото : FieldValueImpl конструктор: ƒ ServerTimestampFieldValueImpl () экземпляра: ServerTimestampFieldValueImpl {_methodName: " FieldValue.serverTimestamp "} arguments: (...) caller: (...)
Mel
Похоже, вы отправили функцию отметки времени в базу данных, а не фактическую отметку времени. Как вы устанавливаете метку времени? firestore.FieldValue.serverTimestamp()
Джош Питтман
Запись, показанная в пожарном магазине, - фотография, которую я приложил. Это запись: this.props.firebase.fieldValue.serverTimestamp ()
Mel
2

Как отправить дату в Firestore:

import firebase from 'firebase/app';

// ..........
// someObject is the object you're saving to your Firestore.

someObject.createdAt: firebase.firestore.Timestamp.fromDate(new Date())

Как читать это обратно:

function mapMonth(monthIndex) {
  const months = {
    0: 'jan',
    1: 'feb',
    2: 'mar',
    3: 'apr',
    4: 'may',
    5: 'jun',
    6: 'jul',
    7: 'aug',
    8: 'sep',
    9: 'oct',
    10: 'nov',
    11: 'dec'
  };
  return months[monthIndex];
}

// ..........
// Here you already read the object from Firestore and send its properties as props to this component.

return(
    <LS.PostDate_DIV>
      Published on {mapMonth(props.createdAt.toDate().getMonth()) + ' '}
      of {props.createdAt.toDate().getFullYear()}
    </LS.PostDate_DIV>
  );
}

По сути, когда вы createdAt.toDate()получаете объект JS Date.

Я использую это все время!

От: https://cloud.google.com/firestore/docs/manage-data/add-data

введите описание изображения здесь

Это создаст данные на основе системной даты пользователя. Если вы хотите быть уверены, что все будет храниться в вашей БД в хронологическом порядке (без каких-либо ошибок в неправильных системных датах, установленных вашей системой пользователей), вам следует использовать временную метку сервера. Дата будет установлена ​​с использованием вашей внутренней системы дат Firestore DB.

введите описание изображения здесь

cbdeveloper
источник
Спасибо за это, но проблема, которую я пытаюсь преодолеть, заключается в том, что я не могу найти способ отображения даты, записанной в базе данных. Я продолжаю получать ошибки, которыми я поделился.
Мел
2

С идентификатором документа пользователя, у которого установлено createdAtсвойство, попробуйте следующее:

const docRef = db.collection("users").doc("[docID]");

docRef.get().then(function(docRef) {
  if (docRef.exists) {
     console.log("user created at:", docRef.data().createdAt.toDate());
  }
})

Мне важно вызвать .data()метод перед доступом к свойствам документа.

Обратите внимание, что если вы обращаетесь docRef.data().createdAt.toDate()к пользователю, для которого createdAtсвойства не установлены, вы получитеTypeError: Cannot read property 'toDate' of undefined

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

//This code gets all the users and logs it's creation date in the console
docRef.get().then(function(docRef) {
  if (docRef.exists && docRef.data().createdAt) {
      console.log("User created at:", docRef.data().createdAt.toDate());
  }
})
Хосе V
источник
Как вы можете видеть выше, я использую data () в моих запросах к полям документа. Если бы я не сделал, другие поля не будут отображаться. Конкретная проблема связана с отметкой времени, которая не отображается. Одна из попыток, которые я предпринял и которые я изложил выше, включает в себя попытку использования расширения toDate (). Это не работает - по причинам, изложенным выше. В любом случае, спасибо за ваше время.
Мел
0

В прошлом я сталкивался с проблемами со свойствами вложенных объектов, которые не отображаются должным образом в списках, где item.somePropон считается объектом, но item.someProp.someSubPropне будет разрешен со значением someSubPropin item.someProp.

Итак, чтобы обойти эту проблему, почему бы не оценить Timestamp для простого объекта даты (или желаемого формата отображения) при создании пользовательского объекта?

this.unsubscribe = this.props.firebase
  .users()
  .onSnapshot(snapshot => {
    let users = [];

    snapshot.forEach(doc =>
      let docData = doc.data();
      docData.createdAt = docData.createdAt.toDate();
      users.push({ ...docData, uid: doc.id }),
    );

    this.setState({
      users,
      loading: false,
    });
  });
samthecodingman
источник
Также стоит отметить, что оба DocumentSnapshot#data()и DocumentSnapshot#get()принимают объект, который указывает, как обрабатывать еще не завершенные FieldValue.serverTimestamp()значения. По умолчанию еще не завершенный будет нулевым. Использование { serverTimestamps: "estimate"}изменит эти нулевые значения на оценку.
samthecodingman
Привет - спасибо за предложение. Я хотел бы попробовать это, но я не понимаю это - или как я могу попытаться осуществить это. Существует ли соглашение о принципах, которые вы применяете, придумывая это предложение? Если я смогу найти литературу о подходе, я постараюсь выяснить, как работает ваша идея, чтобы я мог попробовать ее в своем коде.
Мел
У меня нет никакого конкретного ресурса для этого, поскольку я поднял его после рассмотрения других вопросов StackOverflow в течение многих лет.
samthecodingman
Спасибо, что поделился. Я прочитаю это сегодня вечером
Мел