React - відображення часової позначки firestore


10

Я намагаюся розібратися, як відобразити часову позначку firestore у реагуючому додатку.

У мене є документ firestore з полем з назвою createdAt.

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

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.createAt, я отримую помилку про те, що він знайшов об'єкт із секундами в ньому.

Взявши приклад із Waelmas нижче, я спробував зафіксувати вихід поля як:

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

}

Я також спробував додати це до заяви про карту, але отримав помилку, яка каже, що 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}

Повідомлення про помилку звучить так:

Помилка: Об'єкти недійсні як дитина-реагувач (знайдено: мітка часу (секунди = 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 та createdAt1 генерують один і той же запис бази даних:

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

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

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

Об'єкти не дійсні як дитина-реагувач (знайдено: 15 грудня 2019 21:33:32 GMT + 1100 (австралійський східний літній час)). Якщо ви мали намір надати колекцію дітей, використовуйте замість цього масив

Другий породжує помилку:

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

Я застряг у ідеях, що спробувати далі.

Я побачив цей пост, який говорить про те, що наступне може зробити щось корисне:

                {item.createdAt1.Date.valueOf()}

Це не так. Це робить помилку, яка говорить:

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

Здається, ця публікація має ті ж проблеми, що і я, але не вникає в те, як їм вдалося відобразити збережене значення дати.

Здається, ця публікація застрягла в повідомленні про помилку масиву, але, схоже, з’ясувала, як відобразити дату за допомогою createAt.toDate ()

Відповіді:


1

Після деякої дискусії ми виявили, що часові позначки в об’єкті користувача ОП можуть бути відображені як такі:

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 і отримав таку ж помилку, як і очікувався.

Помилка: Об'єкти недійсні як дитина-реагувач

Мені вдалося отримати це правильне відображення за допомогою наступного методу, який також повинен працювати для вас:

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

Який для моєї часової позначки зразка відображався як:

30.12.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

Я також спробував: createdAt: firebase.firestore.fieldValue.serverTimestamp (). FromDate (нова дата ()), яка повертає помилку, яка говорить: TypeError: Неможливо прочитати властивість 'fieldValue' невизначеного
Mel

Хоча це не спрацювало для мене, мені цікаво зрозуміти, як ви думали спробувати формат, який ви використовували. Це не так, як показано в документації. Якщо я можу дізнатись, як ти виявив щось, що працює для тебе, це може дозволити мені знайти спосіб, який працює для мене (я не розумію, чому це не одне і те саме для всіх - але мені потрібні нові ідеї для того, щоб спробувати ). Ще раз дякую за спробу допомогти.
Мел

Що я можу зробити - це зберегти дату (як показано вище), використовуючи: createdAt: this.props.firebase.fieldValue.serverTimestamp (),
Мель,


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]);
});

Ви отримаєте такий результат:

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


Дякую за приклад. У мене однакова структура в моїй спробі. Він працює для повернення всіх рядкових значень у документі, але не дати. Натомість він створює помилку з повідомленням, яке я розмістив вище. Це не має ніякого сенсу. Я спробував додати розширення toISOString (), але воно не змінює повідомлення про помилку (воно повинно просто бути форматуванням)
Мел,

Чи можете ви записати значення часової позначки в консолі? Просто для підтвердження правильності типу часової позначки Firestore. @Mel
Waelmas

Ні - журнал консолі не працює - він також створює помилку - але дата записується у створене поле в таблиці - тепер я просто намагаюся прочитати його назад. Я створив публікацію, де пояснюється, як я отримав дату для запису (не за документацією на базу даних) тут: stackoverflow.com/questions/59257755/…
Мель

Оскільки ви дотримуєтесь іншого підходу, ніж той, який рекомендували офіційні документи, я не впевнений, що насправді йде не так. Здається, те, як ви створюєте та натискаєте часову позначку в першу чергу, якимось чином несправна. Коли ви зберігаєте мітку часу в Firestore, вона повинна бути об'єктом формату, про який я згадав на початку своєї відповіді. Таким чином він визнається дійсним часовим позначком, який потім може бути використаний з .toDate (). Firestore.Timestamp.now () надасть вам часову позначку правильного формату, щоб перевірити це. @Mel
Waelmas

Я намагався, дотримуючись офіційної документації, створити позначку часу. Я не міг змусити його працювати. Я натрапив на альтернативний спосіб записувати побачення, і тепер не можу прочитати результат! Так засмучує. Все одно дякую за спробу допомогти.
Мел

2

Тож firestore зберігає дати як об'єкт із секундами та наносекундами. Якщо ви хочете часу, коли користувач був створений, тоді ви посилаєтесь user.createdAt.nanoseconds. Це повертає часову позначку unix.

Як ви хочете відображати дату у вашому додатку? Якщо ви хочете отримати об’єкт дати, ви можете передати часову позначку в такий конструктор дат new Date(user.createdAt.nanoseconds). Особисто мені подобається використовувати бібліотеку data-fns для обробки часу.


Дякую - я спробував цю пропозицію. Він повертає помилку, яка говорить: TypeError: Неможливо прочитати властивість "наносекунд" невизначеного. Я перегляну бібліотеку, яку ви запропонували зараз
Мел,

Чи можете ви ввійти у створенеAt та поділитися будь-ласка. Враховуючи характер асинхронізації даних, вам, ймовірно, потрібно просто повернути їх так user.createdAt && new Date(user.createdAt.nanoseconds). Date-fns не допоможе вирішити цю проблему, тому що просто зручна бібліотека для відображення дати після її отримання.
Джош Піттман

createdAt записує довгий список випадаючих меню. Я не можу знайти жодної, що містить дату, показану в полі в firestore. Перша частина: createdAt: ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" прото : FieldValueImpl конструктор: ƒ ServerTimestampFieldValueImpl () примірника: ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" прото : FieldValueImpl конструктор: ƒ ServerTimestampFieldValueImpl () примірника: ServerTimestampFieldValueImpl {_methodName: " FieldValue.serverTimestamp "} аргументи: (...) виклик: (...)
Мел

Це здається, що ви пересунули функцію часової позначки до бази даних, а не фактичну мітку часу. Як ви встановлюєте часову позначку? firestore.FieldValue.serverTimestamp()
Джош Піттман

Запис, показаний у firestore - це фото, яке я додаю. Це запис: this.props.firebase.fieldValue.serverTimestamp ()
Мел

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.

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


Дякую за це, але проблема, яку я намагаюся подолати, полягає в тому, що я не можу знайти спосіб відобразити дату, записану в базі даних. Я продовжую отримувати помилки, якими я поділявся.
Мел

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());
  }
})

Як ви бачите вище, я використовую дані () у своїх запитах для полів документа. Якби не я, інші поля не виводили б. Конкретне питання пов'язане з позначкою часу, яка не відображається. Одна з спроб, яку я зробила, і яку я виклала вище, включає спробу використання розширення toDate (). Це не працює - з причин, викладених вище. Все одно дякую за ваш час.
Мел

0

У минулому у мене виникали проблеми з властивостями вкладених об'єктів, які не відображаються належним чином у списках, де item.somePropвважається об'єктом, але item.someProp.someSubPropне вирішуються зі значенням someSubPropвitem.someProp .

Отже, щоб вирішити проблему, чому б не оцінити часову позначку на звичайний об'єкт дати (або потрібний формат відображення) під час створення об’єкта користувача?

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,
    });
  });

Також варто відзначити, що обидва DocumentSnapshot#data()і DocumentSnapshot#get()приймають об’єкт, який визначає, як обробити ще не завершені FieldValue.serverTimestamp()значення. За замовчуванням, ще не доопрацьований буде просто недійсним. Використання { serverTimestamps: "estimate"}змінить ці нульові значення на оцінку.
samthecodingman

Привіт - дякую за пропозицію. Я хотів би спробувати це, але я не розумію цього - або як я можу спробувати його реалізувати. Чи існує конвенція щодо принципів, які ви застосовуєте, придумуючи цю пропозицію. Якщо я зможу знайти літературу про підхід, я спробую з’ясувати, як працює ваша ідея, щоб я міг спробувати її у своєму коді.
Мел

У мене немає жодного конкретного ресурсу для цього, оскільки я підбирав його, переглядаючи інші питання StackOverflow протягом багатьох років.
samthecodingman

Дякую, що поділились. Я прочитаю їх сьогодні ввечері
Мел
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.