React - hiển thị dấu thời gian Firestore


10

Tôi đang cố gắng tìm ra cách hiển thị dấu thời gian của Firestore trong ứng dụng phản ứng.

Tôi có một tài liệu Firestore với một trường có tên createdAt.

Tôi đang cố gắng đưa nó vào danh sách đầu ra (trích xuất các bit có liên quan ở đây để bạn không phải đọc qua toàn bộ danh sách các trường).

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

Thuộc tính duy nhất không hiển thị là ngày.

Mỗi lần thử trên tạo ra một lỗi cho biết:

TypeError: Không thể đọc thuộc tính 'toDate' không xác định

Tôi đã thấy bài này , và bài nàybài này , và bài này và những người khác như họ, trong đó đề xuất NHCTVN rằng () nên làm việc. Nhưng - tiện ích mở rộng này gây ra lỗi cho tôi - kể cả khi tôi thử tiện ích mở rộng toString.

Tôi biết nó biết có một cái gì đó trong Firestore bởi vì khi tôi thử user.createdAt, tôi gặp lỗi khi nói rằng nó tìm thấy một đối tượng có vài giây trong đó.

Lấy ví dụ từ Waelmas bên dưới, tôi đã cố gắng ghi nhật ký đầu ra của trường dưới dạng:

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

}

Tôi cũng đã thử thêm phần này vào câu lệnh bản đồ của mình nhưng gặp lỗi cho biết user.get không phải là một hàm.

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

Nó tạo ra thông báo lỗi tương tự như trên.

nhập mô tả hình ảnh ở đây

TIẾP THEO TIẾP THEO

Một điều kỳ lạ xuất hiện khi cố gắng tìm cách ghi lại một ngày trong Firestore cho phép tôi đọc lại, đó là khi tôi thay đổi trình xử lý đệ trình của mình dưới một hình thức để sử dụng công thức này:

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

Điều đó làm việc để ghi lại một ngày trong cơ sở dữ liệu.

Hình thức của mục nhập Firestore trông như thế này:

nhập mô tả hình ảnh ở đây

Tôi đang cố gắng hiển thị một ngày trong thành phần này:

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

Khi tôi cố đọc lại - sử dụng:

{item.email}

Thông báo lỗi ghi:

Lỗi: Các đối tượng không hợp lệ dưới dạng con React (được tìm thấy: Dấu thời gian (giây = 1576363035, nano giây = 52000000)). Nếu bạn có ý định kết xuất một bộ sưu tập trẻ em, thay vào đó hãy sử dụng một mảng. trong Mục (tại User Index.jsx: 74)

Khi tôi thử sử dụng từng thử sau:

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

Tôi nhận được một lỗi cho biết:

TypeError: Không thể đọc thuộc tính 'toDate' không xác định

Dựa trên khả năng đọc lại các mục được ghi trong cùng một tài liệu trong các trường khác, tôi hy vọng bất kỳ mục nào trong số này sẽ hoạt động để tạo đầu ra - cả nếu nó không được định dạng theo cách tôi muốn. Điều đó không xảy ra.

TIẾP THEO TIẾP THEO

Lấy ví dụ của Waelmas, tôi đã cố gắng làm theo hướng dẫn, nhưng ở nơi chúng tôi không nhận được phản hồi tương tự là bước đầu tiên. Trong đó Walidia nhận được đầu ra dựa trên phần mở rộng .toDate (), tôi gặp lỗi khi nói toDate () không phải là một hàm.

Phù hợp với tài liệu Firebase, tôi đã thử:

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

}})

Điều này tạo ra một chuỗi lỗi với cú pháp và tôi không thể tìm ra cách khắc phục chúng.

TIẾP THEO TIẾP THEO

Sau đó tôi đã thử tạo một biểu mẫu mới để xem liệu tôi có thể khám phá điều này mà không có khía cạnh xác thực của biểu mẫu người dùng.

Tôi có một hình thức nhận đầu vào là:

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

Trong trường hợp ở dạng trước, nỗ lực Date () mới hoạt động để ghi lại một ngày trong cơ sở dữ liệu, trong ví dụ này cả hai trường cho createdAt và createdAt1 đều tạo cùng một mục cơ sở dữ liệu:

nhập mô tả hình ảnh ở đây

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

Khi tôi cố gắng xuất giá trị của ngày, cái đầu tiên sẽ phát sinh lỗi:

Các đối tượng không có giá trị như một đứa trẻ React (được tìm thấy: CN ngày 15 tháng 12 năm 2019 21:33:32 GMT + 1100 (Giờ ban ngày miền đông Úc)). Nếu bạn có ý định kết xuất một bộ sưu tập trẻ em, thay vào đó hãy sử dụng một mảng

Thứ hai tạo ra lỗi nói:

TypeError: Không thể đọc thuộc tính 'toDate' không xác định

Tôi đang bế tắc về ý tưởng về những gì cần thử tiếp theo.

Tôi thấy bài đăng này cho thấy rằng những điều sau đây có thể làm một cái gì đó hữu ích:

                {item.createdAt1.Date.valueOf()}

Nó không. Nó ám chỉ một lỗi cho biết:

LoạiError: Không thể đọc thuộc tính 'Ngày' không xác định

Bài đăng này dường như có cùng rắc rối với tôi, nhưng không đi sâu vào cách họ quản lý để hiển thị giá trị ngày họ lưu trữ.

Bài đăng này dường như bị kẹt ở thông báo lỗi mảng, nhưng dường như đã tìm ra cách hiển thị một ngày bằng cách sử dụng createdAt.toDate ()

Câu trả lời:


1

Sau một số cuộc thảo luận, chúng tôi thấy rằng dấu thời gian trong đối tượng người dùng OP có thể được hiển thị như sau:

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")}

Tôi đã tạo lại ví dụ của bạn trong một dự án React giả và nhận được lỗi tương tự như mong đợi.

Lỗi: Các đối tượng không hợp lệ là con React

Tôi đã có thể làm cho điều này hiển thị chính xác bằng phương pháp sau, phương pháp này cũng phù hợp với bạn:

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

Mà, đối với dấu thời gian mẫu của tôi, được hiển thị là:

30/12/2019


Hãy chắc chắn rằng bạn đang sử dụng dấu thời gian đã được lưu vào Firestore như:

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

Lưu ý: Điều này giả sử rằng ví dụ của bạn firebase.firestore()là tại this.props.firebase. Trong các ví dụ khác, bạn sử dụng this.props.firebase, nhưng các phương thức đó trông giống như các phương thức trợ giúp mà bạn đã tự tạo.

Khi giá trị này được tìm nạp, nó sẽ là một đối tượng có hai thuộc tính - _seconds_nanoseconds.

Hãy chắc chắn bao gồm dấu gạch dưới. Nếu bạn sử dụng createdAt.secondsnó sẽ không hoạt động, nó phải được createdAt._seconds.


Những thứ khác tôi đã thử:

user.createdAt.toDate()ném toDate() is not a function.

user.createdAt ném Error: Objects are not valid as a React child

new Date(user.createdAt._nanoseconds) kết xuất sai ngày


Xin chào - cảm ơn vì lời đề nghị. Tôi đã thử điều này và nhận được một lỗi cho biết: TypeError: Không thể đọc thuộc tính 'Dấu thời gian' không xác định
Mel

Tôi cũng đã thử: createdAt: firebase.firestore.fieldValue.serverTimestamp (). FromDate (new Date ()), trả về một lỗi có nội dung: TypeError: Không thể đọc thuộc tính 'fieldValue' của không xác định
Mel

Mặc dù điều này không hiệu quả với tôi, tôi rất muốn hiểu cách bạn nghĩ để thử định dạng bạn đã sử dụng. Nó không như trong tài liệu. Nếu tôi có thể tìm hiểu làm thế nào bạn phát hiện ra thứ gì đó phù hợp với bạn, nó có thể cho tôi tìm cách phù hợp với tôi (Tôi không hiểu tại sao những thứ đó không giống với mọi người - nhưng tôi cần những ý tưởng mới cho mọi thứ để thử ). Cảm ơn một lần nữa vì đã cố gắng giúp đỡ.
Mel

Những gì tôi có thể làm là lưu một ngày (như được hiển thị ở trên) bằng cách sử dụng: createdAt: this.props.firebase.fieldValue.serverTimestamp (),
Mel


5

Khi bạn nhận được dấu thời gian từ Firestore, chúng thuộc loại sau:

nhập mô tả hình ảnh ở đây

Để chuyển đổi nó thành dấu thời gian bình thường, bạn có thể sử dụng hàm .toDate ().

Ví dụ: đối với tài liệu như sau:

nhập mô tả hình ảnh ở đây

Chúng ta có thể sử dụng một cái gì đó như:

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

và đầu ra sẽ như sau:

2019-12-16T16:27:33.031Z

Bây giờ để xử lý dấu thời gian đó hơn nữa, bạn có thể chuyển đổi nó thành một chuỗi và sử dụng regex để sửa đổi nó theo nhu cầu của bạn.

Ví dụ: (Tôi đang sử dụng Node.js tại đây)

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

Sẽ cung cấp cho bạn một đầu ra như thế này:

nhập mô tả hình ảnh ở đây


Cảm ơn bạn cho ví dụ. Tôi có cấu trúc tương tự trong nỗ lực của tôi. Nó hoạt động để trả về tất cả các giá trị chuỗi trong tài liệu nhưng không phải là ngày. Thay vào đó, nó tạo ra một lỗi với thông báo tôi đã đăng ở trên. Nó không có nghĩa gì cả. Tôi đã thử thêm tiện ích mở rộng toISOString () nhưng nó không thay đổi thông báo lỗi (đó chỉ là định dạng)
Mel

Bạn có thể đăng nhập giá trị của dấu thời gian trong giao diện điều khiển không? Chỉ cần xác nhận đó là loại dấu thời gian Firestore chính xác. @Mel
Waelmas

Không - nhật ký giao diện điều khiển không hoạt động - nó cũng tạo ra lỗi - nhưng ngày được ghi lại trong trường createdAt trong bảng - bây giờ tôi chỉ đang cố đọc lại. Tôi đã tạo một bài đăng giải thích làm thế nào tôi có ngày ghi lại (không phải theo tài liệu về căn cứ hỏa lực) tại đây: stackoverflow.com/questions/59257755/ Kẻ
Mel

Vì bạn đang theo một cách tiếp cận khác với cách tiếp cận được đề xuất bởi các tài liệu chính thức, tôi không chắc điều gì đang thực sự sai. Có vẻ như cách bạn đang tạo và đẩy dấu thời gian ở vị trí đầu tiên là một cách nào đó bị lỗi. Khi bạn lưu trữ dấu thời gian cho Firestore, nó cần phải là một đối tượng có định dạng mà tôi đã đề cập ở đầu câu trả lời của tôi. Bằng cách này, nó được nhận dạng là dấu thời gian hợp lệ mà sau đó có thể được sử dụng với .toDate (). Firestore.Timestamp.now () sẽ cung cấp cho bạn dấu thời gian đúng định dạng để kiểm tra. @Mel
Waelmas

Tôi đã thử làm theo các tài liệu chính thức để tạo ra một dấu thời gian. Tôi không thể làm cho nó hoạt động. Tôi tình cờ tìm thấy một cách khác để ghi lại một ngày và bây giờ không thể đọc lại đầu ra! Rất bực bội. Dù sao cũng cảm ơn vì đã cố gắng giúp đỡ.
Mel

2

Vì vậy, Firestore lưu trữ ngày tháng như một đối tượng với giây và nano giây. Nếu bạn muốn thời gian người dùng được tạo thì bạn sẽ tham khảo user.createdAt.nanoseconds. Điều này trả về một dấu thời gian unix.

Bạn muốn hiển thị ngày vào trong ứng dụng của bạn như thế nào? Nếu bạn muốn có được một đối tượng ngày thì bạn có thể chuyển dấu thời gian vào một hàm tạo ngày như vậy new Date(user.createdAt.nanoseconds). Cá nhân tôi thích sử dụng thư viện date-fns để xử lý thời gian.


Cảm ơn - Tôi đã thử đề nghị này. Nó trả về một lỗi cho biết: TypeError: Không thể đọc thuộc tính 'nano giây' không xác định. Tôi sẽ xem thư viện mà bạn đề xuất ngay bây giờ
Mel

Bạn có thể đăng nhập createdAt và chia sẻ không. Do tính chất không đồng bộ của dữ liệu, có lẽ bạn chỉ cần trả lại dữ liệu như vậy user.createdAt && new Date(user.createdAt.nanoseconds). Date-fns sẽ không giúp đỡ với vấn đề này, đó chỉ là một thư viện tiện dụng để hiển thị ngày sau khi bạn có nó.
Josh Pittman

createdAt ghi lại một danh sách dài các menu thả xuống. Tôi không thể tìm thấy một cái có chứa ngày được hiển thị trên cánh đồng ở Firestore. Phần đầu tiên là: createdAt: ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" proto : FieldValueImpl constructor: ServerTimestampFieldValueImpl ƒ () Ví dụ: ServerTimestampFieldValueImpl _methodName: "FieldValue.serverTimestamp" proto : FieldValueImpl constructor: ƒ ServerTimestampFieldValueImpl () Ví dụ: ServerTimestampFieldValueImpl {_methodName: " Đối số FieldValue.serverTimestamp "}: (...) người gọi: (...)
Mel

Có vẻ như bạn đã đẩy chức năng dấu thời gian vào cơ sở dữ liệu, không phải là dấu thời gian thực tế. Làm thế nào bạn thiết lập dấu thời gian? firestore.FieldValue.serverTimestamp()
Josh Pittman

Các mục hiển thị trong Firestore là hình ảnh tôi đính kèm. Đây là mục: this.props.firebase.fieldValue.serverTimestamp ()
Mel

2

Cách gửi ngày đến Firestore:

import firebase from 'firebase/app';

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

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

Làm thế nào để đọc lại:

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

Về cơ bản khi bạn createdAt.toDate()nhận được một đối tượng Ngày JS.

Tôi sử dụng nó như thế này mọi lúc!

Từ: https://cloud.google.com/firestore/docs/manage-data/add-data

nhập mô tả hình ảnh ở đây

Điều này sẽ tạo ra một dữ liệu dựa trên ngày hệ thống của người dùng. Nếu bạn cần chắc chắn rằng mọi thứ sẽ được lưu trữ theo trình tự thời gian (không có bất kỳ lỗi sai ngày hệ thống nào được đặt bởi hệ thống người dùng của bạn) trên DB của bạn, bạn nên sử dụng dấu thời gian của máy chủ. Ngày sẽ được đặt bằng hệ thống ngày nội bộ Firestore DB của bạn.

nhập mô tả hình ảnh ở đây


Cảm ơn vì điều này, nhưng rắc rối tôi đang cố gắng khắc phục là tôi không thể tìm ra cách hiển thị ngày được ghi trong cơ sở dữ liệu. Tôi liên tục nhận được lỗi của các loại tôi đã chia sẻ.
Mel

2

Với ID tài liệu của Người dùng có bộ thuộc createdAttính, hãy thử các cách sau:

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

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

Tôi rất quan trọng để gọi .data()phương thức trước khi truy cập các thuộc tính của tài liệu

Lưu ý rằng nếu bạn truy cập docRef.data().createdAt.toDate()của người dùng mà createdAtkhông đặt quyền thích hợp, bạn sẽ nhận đượcTypeError: Cannot read property 'toDate' of undefined

Vì vậy, trong trường hợp bạn có bất kỳ người dùng nào trong bộ sưu tập của bạn không có thuộc createdAttính được xác định. Bạn nên thực hiện một logic để kiểm tra xem người dùng có thuộc createdAttính hay không trước khi nhận nó. Bạn có thể làm một cái gì đó như thế này:

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

Như bạn có thể thấy ở trên, tôi sử dụng dữ liệu () trong các yêu cầu của tôi cho các trường tài liệu. Nếu tôi không các lĩnh vực khác sẽ không kết xuất. Vấn đề cụ thể là với dấu thời gian, không hiển thị. Một trong những nỗ lực tôi đã thực hiện và tôi đã nêu ở trên, bao gồm nỗ lực sử dụng tiện ích mở rộng toDate (). Nó không hoạt động - vì những lý do được nêu ở trên. Dù sao cũng cảm ơn thời gian của bạn.
Mel

0

Tôi đã gặp vấn đề trong quá khứ với các thuộc tính đối tượng lồng nhau không hiển thị đúng trong danh sách item.somePropđược coi là một đối tượng, nhưng item.someProp.someSubPropsẽ không giải quyết với giá trị someSubProptrong item.someProp.

Vì vậy, để giải quyết vấn đề, tại sao không đánh giá Dấu thời gian cho một đối tượng ngày đơn giản (hoặc định dạng hiển thị mong muốn) khi tạo đối tượng người dùng?

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

Cũng đáng lưu ý rằng cả hai DocumentSnapshot#data()DocumentSnapshot#get()chấp nhận một đối tượng chỉ định cách xử lý FieldValue.serverTimestamp()các giá trị chưa hoàn thành . Theo mặc định, một chưa hoàn thành sẽ chỉ là null. Sử dụng { serverTimestamps: "estimate"}sẽ thay đổi các giá trị null thành ước tính.
samthecodingman

Xin chào - cảm ơn vì lời đề nghị. Tôi muốn thử nhưng tôi không hiểu - hoặc làm thế nào tôi có thể thử thực hiện nó. Có một quy ước cho các nguyên tắc bạn đang áp dụng khi đưa ra gợi ý này. Nếu tôi có thể tìm tài liệu về cách tiếp cận, tôi sẽ cố gắng tìm hiểu ý tưởng của bạn hoạt động như thế nào để tôi có thể thử nó trong mã của mình.
Mel

Tôi không có bất kỳ tài nguyên cụ thể nào cho nó, vì tôi đã chọn nó sau khi xem các câu hỏi khác về StackOverflow trong những năm qua.
samthecodingman

Cám ơn vì đã chia sẻ. Tôi sẽ đọc những thứ này tối nay
Mel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.