So I am trying to get a timestamp on the time a post is made, but fire.database.ServerValue.TIMESTAMP doesn't seem to be working in the addTicket function. When I post the ticket, it doesn't load to the Pending page, and just has variables ticketTitle & ticketBody in the Ask URL. I think I am just confused on how the timestamp works in firebase. How do I properly add the timestamp of the post to the database tuple?
Ask.js:
import React, { Component } from 'react';
import AskForm from '../../components/AskForm.js';
import fire from '../../config/Fire.js';
import { Link, withRouter } from 'react-router-dom'
class Ask extends Component {
constructor(props){
super(props);
this.addTicket = this.addTicket.bind(this);
this.database = fire.database().ref().child('tickets');
this.state = {
tickets: [],
userId: this.props.user.uid
}
}
componentDidMount(){
fire.database().ref('/users/' + this.props.user.uid).once('value').then(function(snapshot) {
var FirstName = (snapshot.val() && snapshot.val().userFirstName);
// ...
console.log(FirstName);
});
}
addTicket(title, body){
this.database.push().set({ ticketUserId: this.props.user.uid, ticketTitle: title, ticketBody: body, ticketStatus: 'pending', ticketTime: fire.database.ServerValue.TIMESTAMP});
alert("Your question has been submitted.")
this.props.history.push('/pending')
}
render() {
return (
<div>
<div className="m-container">
</div>
<div>
<AskForm addTicket={this.addTicket} />
</div>
</div>
);
}
}
export default withRouter(Ask);
AskForm.js
import React, { Component } from 'react';
class AskForm extends Component{
constructor(props){
super(props);
this.state = {
ticketBody: '',
ticketTitle: ''
};
this.handleChange = this.handleChange.bind(this);
this.writeTicket = this.writeTicket.bind(this);
}
// When the user input changes, set the ticketTitle or ticketBody
// to the value of what's in the input box.
handleChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
writeTicket(){
if(this.state.ticketTitle === '' || this.state.ticketBody === ''){
alert('Please complete all fields.')
} else {
// Call a method that sets the ticketTitle and ticketBody for a ticket to
// the value of the input
this.props.addTicket(this.state.ticketTitle, this.state.ticketBody);
// Set inputs back to an empty string
this.setState({
ticketBody: '',
ticketTitle: ''
})
}
}
render(){
return(
<div class="s-container">
<form>
<label for="ticketTitle">Title: </label>
<input
id="ticketTitle"
name="ticketTitle"
type="text"
placeholder="A short sentence to identify your issue"
value={this.state.ticketTitle}
onChange={this.handleChange}
/>
<br/>
<br/>
<label for="ticketBody">Description: </label>
<textarea
id="ticketBody"
name="ticketBody"
placeholder="Placeholder"
value={this.state.ticketBody}
onChange={this.handleChange}
/>
<button
className="m-btn"
onClick={this.writeTicket}>
Submit
</button>
</form>
</div>
)
}
}
export default AskForm;
Revisited my question:
I need to import firebase directly using import * as firebase from 'firebase'; instead of from my config file. Then just pushed the time value to the database with my other values. See below for example.
Code:
import * as firebase from 'firebase';
addMessage(body){
this.questionDatabase.child(this.state.questionId).child('messages').push().set({
messageUserId: fire.auth().currentUser.uid,
messageBody: body,
time: firebase.database.ServerValue.TIMESTAMP
});
}
This works to create a timestamp client side is using firestore: (In this case I export it from my main firebase.js file)
import firebase from "firebase/compat/app";
import "firebase/compat/firestore";
export const serverStamp = firebase.firestore.Timestamp
To use it after importing serverStamp:
var stampNow = serverStamp.now()
Related
I have a class with form and I want to pass entered data to next jsx file =>
Here is class ("sender")
import React from 'react'
import Button from './Button';
class Sender extends React.Component {
constructor() {
super();
this.state = {
imie: '',
};
this.redirect = this.redirect.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleChange({ target }) {
this.setState({
[target.name]: target.value
});
}
getData(){
const sendData = [
{
name: this.state.name
}
]
}
render() {
return (
<div className="order-wrapper">
<div className="order">
<div className="order-box">
<label htmlFor="name">Imie: </label>
<input
type="text"
name="name"
id="name"
value={ this.state.name }
onChange={ this.handleChange }
/>
</div>
<div className="order-box">
<Button
type="submit"
value="Zamów"
className="zamowbtn"
onClick={this.redirect}
/>
</div>
</div>
</div>
</div>
)
}
}
export default Sender
From this class I want to send name value which is located in getData() function.
I need that value in .jsx file below and show it in console.log(). How to do it? Please help me:)
import React from 'react'
import Sender from './Sender'
const Finish = () => {
return (
<div>
{ /* Here i need my 'name' value from Sender Class */ }
</div>
)
}
export default Finish
If there are in different parts of Application and one is not a parent of second one. You should use Context API for this
I want to create an input field in React.
It basically should display the entered input real-time (managed this part).
However, it also should display a message "no data provided!" when nothing was entered.
My if statement isn't working? Why?
import React from "react"
import ReactDOM from "react-dom"
class Exercise1 extends React.Component {
constructor() {
super()
this.state = {
firstName:""
}
this.handleChange = this.handleChange.bind(this)
}
handleChange (event) {
this.setState({
[event.target.name]: event.target.value
})
}
render() {
let display
if(this.state.firstname != "") {
display=this.state.firstName
} else {
display="no data provided!"
}
return (
<div>
<form>Input:
<input
type="text"
name="firstName"
placeholder = "no data provided!"
value={this.state.firstName}
onChange={this.handleChange}
/>
</form>
<h1>{display}</h1>
</div>
)
}
}
export default Exercise1
PS: please stick with your answer as much as possible to the code above since I am a beginner and can't follow too different approaches.
You have a typo here. Your state variable is firstName (with capital N), but you are trying to check condition with firstname (with small n). You should do this,
if(this.state.firstName != "") {
display = this.state.firstName
} else {
display = "no data provided!"
}
Demo
Hi you can use your if like this
import React from "react"
import ReactDOM from "react-dom"
class Exercise1 extends React.Component {
constructor() {
super()
this.state = {
firstName:""
}
}
handleChange = (event) => {
this.setState({
[event.target.name]: event.target.value
})
}
render() {
const { firstName } = this.state
return (
<div>
<form>Input:
<input
type="text"
name="firstName"
placeholder = "no data provided!"
value={this.state.firstName}
onChange={this.handleChange}
/>
</form>
<h1>{firstName ? firstName : "no data provided!"}</h1>
</div>
)
}
}
export default Exercise1
I have a few components that each contain inputs, and on the main component I have a button that will send that information all at once to the server. The problem is that the main component that has the button doesn't have the input content of the child components.
In the past I've passed down a method that would send the content back up into the state, but is there an easier less painful way of doing it? It just feels like an odd way of doing that.
Here's a short example of what I have and what I mean.
Main component:
import React from 'react';
import { Button } from 'react-toolbox/lib/button';
import Message from './Message';
class Main extends React.Component {
constructor() {
super();
this.state = { test: '' };
}
render() {
return (
<div className="container mainFrame">
<h2>Program</h2>
<Message />
</div>
);
}
}
export default Main;
And the message component:
import React from 'react';
import axios from 'axios';
import Input from 'react-toolbox/lib/input';
class Message extends React.Component {
constructor() {
super();
this.state = { message: '' };
this.handleChange = this.handleChange.bind(this);
}
handleChange(value) {
this.setState({ message: value });
}
render() {
return (
<Input
type="text"
label="Message"
name="name"
onChange={this.handleChange}
/>
);
}
}
export default Message;
To answer your question, yes. You can try using refs. Add a ref to Message component, and you will be able to access the child component's methods, state and everything. But thats not the conventional way, people generally use callbacks, as you mentioned earlier.
import React from 'react';
import { Button } from 'react-toolbox/lib/button';
import Message from './Message';
class Main extends React.Component {
constructor() {
super();
this.state = { test: '' };
}
clickHandler () {
let childState = this.refs.comp1.state //returns the child's state. not prefered.
let childValue = this.refs.comp1.getValue(); // calling a method that returns the child's value
}
render() {
return (
<div className="container mainFrame">
<h2>Program</h2>
<Message ref="comp1"/>
<Button onClick={this.clickHandler} />
</div>
);
}
}
export default Main;
import React from 'react';
import axios from 'axios';
import Input from 'react-toolbox/lib/input';
class Message extends React.Component {
constructor() {
super();
this.state = { message: '' };
this.handleChange = this.handleChange.bind(this);
}
handleChange(value) {
this.setState({ message: value });
}
getValue () {
return this.state.message;
}
render() {
return (
<Input
type="text"
label="Message"
name="name"
onChange={this.handleChange}
/>
);
}
}
export default Message;
You are doing what is suggested in docs so it's a good way.
I have a button that will send that information all at once to the server
I assume then it might be form you can use. If so you can just handle onSubmit event and create FormData object containing all nested input field names with their values (even in children components). No need for callbacks then.
handleSubmit(e){
e.preventDefault();
const form = e.currentTarget;
const formData = new FormData(form); // send it as a body of your request
// form data object will contain key value pairs corresponding to input `name`s and their values.
}
checkout Retrieving a FormData object from an HTML form
I have a simple React component which pulls in some data via the Monzo API and then I simply want to print it out on the screen. I can see I'm getting back the correct data via the React dev tools and it's setting the state however nothing gets printed in my HTML.
Here is my component:
import React, {Component} from "react";
import "./App.css";
import axios from "axios";
class App extends Component {
constructor(props) {
super(props);
this.state = {
account: [{
id: '',
description: '',
created: '',
type: ''
}]
}
}
componentDidMount() {
let config = {
headers: {
'Authorization': 'Bearer sampleToken'
}
};
axios.get('https://api.monzo.com/accounts', config).then((response) => {
this.setState({'account': response.data.accounts});
});
}
render() {
return (
<div className="App">
<div className="App-header">
<h2>Hello {this.state.account.map(account =>
console.log(account),
<p>account.description</p>
)}</h2>
</div>
<p className="App-intro">
Monzo API app
{this.state.account.id}
</p>
</div>
);
}
}
export default App;
My console log within my map function first displays an empty account object and then a filled correct account object, could this be the reason why?
<p>{account.description}</p>
instead of
<p>account.description</p>
I'm trying to build an example CRUD app with React and React Router, and I can't figure out why state isn't passing into a child component the way I'm expecting it to. When I hit the edit route, it renders the Edit component, which grabs the kitten I want from the database and sends it's info to a Form component which is used both for editing an existing kitten or adding a new one.
Here's the Edit component:
import React, { Component } from 'react';
import axios from 'axios';
import { match } from 'react-router-dom';
import Form from './Form';
export default class Edit extends Component {
constructor(props) {
super(props)
this.state = {}
}
componentDidMount() {
axios.get(`/updateKitten/${this.props.match.params.id}`)
.then(res => {
const kitten = res.data
this.setState({ kitten })
console.log(this.state.kitten.name) //Sammy, or something
})
.catch(err => console.log(err))
}
render() {
return (
<Form
name={this.state.kitten.name} // throws error or undefined
description={this.state.kitten.description} //throws error or undefined
route={this.props.match.params.id}
/>
)
}
}
The Edit component passes name, description, and route to this Form component:
import React, { Component } from 'react';
import axios from 'axios';
export default class Add extends Component {
constructor(props) {
super(props)
this.state = { name: this.props.name, description: this.props.description}
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(e) {
const name = e.target.name;
const value = e.target.value;
this.setState({
[name]: value
});
}
handleSubmit(e) {
axios.post(`/addKitten/${this.props.route}`, this.state)
.then(this.setState({ name: '', description: '' }))
e.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>Name</label>
<input type='text' name="name" value={this.state.name}
onChange={this.handleChange}/>
<label>Description</label>
<input type='text' name="description" value={this.state.description}
onChange={this.handleChange}/>
<input type='submit' value='Submit' />
</form>
)
}
}
And I get the following error:
bundle.js:28950 Uncaught TypeError: Cannot read property 'name' of undefined
from trying to send that info as props to the Form component.
What am I doing wrong?
Two things,
First: In your edit component, you have not initialised kitten state and you are setting it based on the API result. However, componentDidMount is called after the component has been called and hence the DOM has been rendered once and the first time it did not find any value as this.state.kitten.name or this.state.kitten.description .
Its only after the API is a success that you set the kitten state. Hence just make a check while rendering.
Second: You have console.log(this.state.kitten.name) after the setState function. However setState is asynchronous. See this question:
Change state on click react js
and hence you need to specify console.log in setState callback
You code will look like
export default class Edit extends Component {
constructor(props) {
super(props)
this.state = {}
}
componentDidMount() {
axios.get(`/updateKitten/${this.props.match.params.id}`)
.then(res => {
const kitten = res.data
this.setState({ kitten }. function() {
console.log(this.state.kitten.name) //Sammy, or something
})
})
.catch(err => console.log(err))
}
render() {
return (
<Form
name={this.state.kitten.name || '' }
description={this.state.kitten.description || ''}
route={this.props.match.params.id}
/>
)
}
}
When your Edit component loads for the first time, it doesn't have a kitten. Hence the error.
What you need to do is the create an empty kitten. In your Edit component...
this.state = { kitten: {name:''} }
This will set the kitten's name to an empty string on the very first mount/render of your component.