Reacjs/Graphql: Pass variables values to query from event - reactjs

So the code below is updating the state of inputValue but for some reason that value is not be passed to the query as the following error is shown:
[GraphQL error]: Message: Variable "$timestamp" of required type "Float!" was not provided., Location: [object Object], Path: undefined
So my question is how do I assign the inputValue to timestamp and pass timestamp to the getObjectsQuery?
class Calendar extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: ""
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit = event => {
event.preventDefault();
console.log(this.state.inputValue);
this.setState({
inputValue: new Date(document.getElementById("time").value).valueOf()
}); //Parent component contains submit button and there lives state. Submit handler should only set value in state with...setState()- NOT directly
this.props.data.refetch({
//For some reason
timestamp: this.state.inputvalue
});
console.log(this.state.inputValue);
};
render() {
console.log(this.props);
return (
<div className="Calendar">
<form onSubmit={this.handleSubmit.bind(this)}>
<label>Date/Time</label>
<input type="datetime-local" id="time" step="1" />
<input type="submit" value="Submit" />
</form>
</div>
//{this.render(){return (<UserList />)};
);
}
}
export default graphql(getObjectsQuery, {
options: props => ({
variables: {
timestamp: props.inputvalue
}
})
})(Calendar);

I know it's already solved in another place Reactjs/Graphql: TypeError: Object(...) is not a function
Just to remember (as you stil not learned):
handleSubmit = event => {
event.preventDefault();
console.log(this.state.inputValue); // OLD VALUE
this.setState({
inputValue: new Date(document.getElementById("time").value).valueOf()
});
this.props.data.refetch({
//For some reason
timestamp: this.state.inputvalue
// THERE IS STILL OLD VALUE
// because setState work asynchronously
// IT WILL BE UPDATED LATER
});
console.log(this.state.inputValue); // STILL OLD VALUE
};
To use value from event you could simply use its value, not passing it through 'async buffer' (state).
handleSubmit = event => {
event.preventDefault();
console.log(this.state.inputValue); // OLD VALUE
const timestamp = new Date(document.getElementById("time").value).valueOf()
console.log(timestamp); // NEW VALUE
// use new value directly
this.props.data.refetch({
timestamp: +timestamp
// convert to int
});
// save in state - IF NEEDED at all
this.setState({
inputValue: timestamp
});
};
Of course using setState callback is a quite good workaround, too.
Keep in ming that you can have 2 renders - one when state changes and second when data arrives. If storing value in state isn't really required you can avoid one unnecessary rendering.

Related

React app, after getting data from initial get request, onChange doesnt work

constructor (props) {
super(props)
this.state = {
AyarAdi: '',
Bilgi: '',
FirmaKodu: '',
icerik: {
smsUser: '',
smsApi: '',
mesajAciklama: '',
password: ''
},
errors: {}
}
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
componentDidMount () {
this.props.AyarlarListesiAl(this.props.user.userCreds.FirmaKodu)
}
handleChange (event) {
this.setState({
icerik: {
...this.state.icerik,
[event.target.name]: [event.target.value]
}
})
}
render(){
<div>
<InputGroup className='mb-3'>
<FormControl
name='password'
placeholder='SMS Şifre'
onChange={this.handleChange}
value={
this.props.data.AyarlarListesi[0] !== undefined
? JSON.parse(this.props.data.AyarlarListesi[0].Bilgi).password
: this.state.icerik.password
}
style={{ maxWidth: 400, height: 40 }}
/>
<span style={{ color: 'red' }}>
{this.state.errors['password']}
</span>
</InputGroup>
</div>
}
const mapStateToProps = state => ({
user: state.user,
data: state.data
})
....
The problem is, in componentDidMount, I send a get request to the server via Redux action, and it gets me data from the redux reducer state; AyarlarListesi. I wanted to fetch the data to the input elements value, So when a user opens the page, he/she can update the previous data just changing it on the input and clicks to submit. I can successfully put the data to the input but I can't change the value of the input, it stays stable, the handleChange function doesn't work. How can I make it work?
Your handleChange function only manipulates the state. However the value to be displayed comes preferrably from props and only if the props field is not available it will fall back to the state variable.
To display the state variable after changing it via user input, you could either swap the condition and make it so the state variable will be displayed unless it's empty (and use the props variable as a fallback) or you could instead update the state variable initially when you get new props.
Assuming you never change props from outside or don't care about later updates, this would be my preferred way of solving your problem:
componentDidMount () {
this.props.AyarlarListesiAl(this.props.user.userCreds.FirmaKodu);
if (this.props.data.AyarlarListesi[0] !== undefined) {
this.setState({
icerik: {
...this.state.icerik,
password: JSON.parse(this.props.data.AyarlarListesi[0].Bilgi).password,
},
});
}
}
Also in your FormControl skip checking if the props data is set and instead always use this.state.icerik.password as the value.
If your props from outside could change and you'd like to restart whenever a new password or AyarlarListesi is passed from outside, you should update the state in componentDidUpdate again:
componentDidUpdate (prevProps) {
if (prevProps.data.AyarlarListesi !== props.data.AyarlarListesi && props.data.AyarlarListesi[0] !== undefined) {
this.setState({
icerik: {
...this.state.icerik,
password: JSON.parse(this.props.data.AyarlarListesi[0].Bilgi).password,
},
});
}
}

Setting state with the value of a react-dateTime component

please I need help. I'm using a react-dateTime component, and I am simply trying to get the value of that component just like every other field in a form. But I am unable to get the value of the selected date let alone store it in a state with the other attributes on other fields.
Here is my code:
Datetime component
<Datetime
onChange={this.handleChange}
value={startDate}
timeFormat={true}
name="startDate"
inputProps={{ placeholder: "Start Date" }}
/>
event handler
handleChange = event => {
this.setState({ [event.target.name]: event.target.value });
};
second onchange handler
handleSelectDate = event => {
if (event.target.name === "startDate") {
this.setState({ startDate: event.target.value});
} else {
this.setState({ endDate: event.target.value });
}
}```
The state object
this.state= { startDate: '' }
I have tried different approaches, currently I get an error that event.target is undefined, so there is no event at all, I have also tried to initialize the handler by calling event there onChange
Thanks
It doesn't work like regular input to get its value by name
onChange: Callback trigger when the date changes. The callback receives the selected moment object as only parameter, if the date in the input is valid. If the date in the input is not valid, the callback receives the value of the input (a string). Docs
Try this:
class App extends React.Component {
state = {
startDate: ""
}
// You need to bind "this"
handleChange = this.handleChange.bind(this)
// Receives the selected "moment" object as only parameter
handleChange(date) {
this.setState({ startDate: date })
}
render() {
return (
<div>
<Datetime
value={this.state.startDate}
onChange={this.handleChange}
timeFormat={true}
inputProps={{ placeholder: "Start Date" }}
/>
<hr />
Select date:{" "}
{this.state.startDate ? this.state.startDate.toString() : "no selected date"}
</div>
)
}
}
Check this codeSandbox example.
Although it works, it's kinda outdated and I encourage you to check react-datetime-picker or react-date-picker

I wanna console.log the value after clicking the submit button once and to delete the previous mapped items, but it doesnt work

I'm very new to react and I got two problems:
I want to console log the input and display the mapped data after clicking the submit button once. But I get console logged the input and the mapped data after clicking the button twice.
I wanna clear the mapped list (data from previous input) and display new list items depending on the input. But the new list items are only added to the end of the previous list (only the last list item from the previous list got overwritten by the first list item of the new list).
So this is the code from my app component:
import React, { Component, Fragment } from 'react';
import './App.css';
import Display from './/Display';
class App extends Component {
constructor(props) {
super(props);
this.state = {
value: "",
passedValue: ""
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({ value: event.target.value });
}
handleSubmit(event) {
this.setState({ passedValue: this.state.value });
console.log(this.state.passedValue);
event.preventDefault();
}
render() {
return (
<div>
<form className="inputContainer" onSubmit={this.handleSubmit}>
<input type="text" name="company_name" onChange={this.handleChange} />
<input type="submit" value="Submit" />
</form>
<Display listDataFromParent={this.state.passedValue} />
</div>
);
}
}
export default App;
And this is my display component:
import React, { Component } from 'react'
import "./Display.css";
export default class Display extends Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
data: []
};
}
componentWillReceiveProps() {
fetch("http://localhost:5000/company?company_name=" + this.props.listDataFromParent)
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
data: result
});
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
}
render() {
const { error, isLoaded, data } = this.state;
// if (error) {
// return <div>Error: {error.message}</div>;
// } else if (!isLoaded) {
// return <div>Loading...</div>;
// } else {
return (
<div className="display">
<h1>Kreditnehmer</h1>
<ul>
{this.props.listDataFromParent}
{data.map(item => (
<li key={item.c.company_id}>
Relation type: {item.r.relation_group}
Last name: {item.p.last_name}
</li>
))}
</ul>
</div>
);
}
}
Can anyone help?
1) setState is async method in react means it will take some time to update the component state. You can get your console log by using callback function of setState like
this.setstate({ value: e.target.value }, () => { console.log(this.state.value) });
2) in display component, your using componentWillReciveProps life cycle and inside that your using this.props.listdatafromparent which is pointing previous props. Rather than using this.props I would suggest consider props param of life cycle, means it should be like
componentWillReciveProps(props) {
// your code
Console.log(props.listdatafromparent);
}
The handleSubmit method is wrong... the console log is executed before the state is changed. You need to put it inside a callback function as a second parameter of setState.
this.setState({ passedValue: this.state.value }, () => {
console.log(this.state.passedValue);
});
Answers are:
1) Callback function should be used on setState, in order to do console.log after state is really updated.
In your case you call setState and setState is async function, which means that console.log won't wait until state is really updated.
Your code should be:
handleSubmit(event) {
this.setState({ passedValue: this.state.value },
() => console.log(this.state.passedValue));
event.preventDefault();
}
2) I would move data fetching out of componentWillReceiveProps(), since this lifecycle method will be deprecated from version 17 and it is fired on every render(). Try replacing with componentDidMount() or componentDidUpdate(). Maybe just this small change will solve your problem. If not pls post results and I will take a look again.

function onHandleChange won't work until after I've selected both options in the select tag

The function onHandleChange won't work until after I've selected both options in the select tag, then it start to work properly.I'm trying to render a chart based on which data the function gets. I'm curious to understand why this happens and where I'm making my mistake. Could someone please point to me where I'm making my mistake or if there's any mistake at all? I'm fairly new to React.js and programming in general.
This doesn't seemed to work until after I've selected both options from the select tag:
onHandleChange = (data, listDataFromChild) => {
if(this.state.listDataFromChild === 'oneYear'){
this.setState({
data:oneYear
})
} else if(this.state.listDataFromChild === 'twoYear'){
this.setState({
data:twoYear
})
}
}
Here's the component from which the function onHandleChange gets it's data from:
export class SelectionBoxYear extends React.Component {
constructor(props) {
super(props);
this.state = {
value: 'oneYear'
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({
value: e.target.value
},()=>{
let { value } = this.state;
this.props.callbackFromParent(value);
this.props.onHandleChange(value, this.props.dataFromParent)
});
}
render() {
return(
<div>
<label>
<p>Select the year of the investment:</p>
<select value={this.state.value} onChange={this.handleChange}>
<option value="oneYear">One year ago</option>
<option value="twoYear">Two years ago</option>
</select>
</label>
</div>
)
}
}
Here's the full code: https://github.com/vtrpza/chart/tree/master/my-app/src
From React's documentation
setState() does not immediately mutate this.state but creates a
pending state transition. Accessing this.state after calling this
method can potentially return the existing value. There is no
guarantee of synchronous operation of calls to setState and calls may
be batched for performance gains.
In SelectionBoxYear.js file you need to put the onHandleChange and callbackFromParent functions in the callback of set state
handleChange(e) {
this.setState({
value: e.target.value
},()=>{
let { value } = this.state;
this.props.callbackFromParent(value);
this.props.onHandleChange(value, this.props.dataFromParent)
});
}

ReactJS, Checkbox doesn't

I Have a ReactJS checkbox component. When onChange is called I can log the new state and see it changing, but it never actually re-renders the checkbox into the new state. So the ADD_ID action is never called. See code below:
class CheckBox extends React.Component {
constructor(props) {
super(props)
this.state = {
checked: true
}
}
changing = (e) => {
this.setState(prevState => ({checked: !prevState.checked}), () => {
console.log(this.state.checked); // false
this.state.checked
? store.dispatch({ type: 'ADD_ID', id: this.props.id })
: store.dispatch({ type: 'REMOVE_ID', id: this.props.id });
});
}
render() {
return (
<label>
Include
<input onChange={this.changing} checked={this.state.checked} type='checkbox'/>
</label>
)
}
}
Is there a lifecycle hook that I have to call? I was under the impression that the component would re-render when either it's props or state changes, in this case, as shown by the console.log(this.state.checked), the state has changed, but the component doesn't re-render.
The event has already a checked property for you. You're doing it in a way that's a bit weird.
Change your function to something like:
handleChange = (e) => {
const isChecked = e.target.checked
if(isChecked){
store.dispatch({type:'ADD_ID', id:this.props.id})
} else {
store.dispatch({type:'REMOVE_ID', id:this.props.id})
}
this.setState(checked: isChecked)
}
It's however still strange that you're using at the same time internal state and Redux. You may want to rethink your approach here.
React docs on forms, which I recommend you to read in 5 min:
https://reactjs.org/docs/forms.html

Resources