Pass form input value to method in react - javascript

I am struggling with a situation where I need to grab the value of an input field to make an API call.
So What I have is this:
import React, { Component } from 'react'
import axios from 'axios';
const fetchWeather = function (e) {
e.preventDefault();
axios.get('https://api.openweathermap.org/data/2.5/weather?q=Zeist&appid=MYID')
.then(res => {
console.log(res.data);
});
console.log();
}
export default class App extends Component {
render() {
return (
<div>
<form onSubmit = {fetchWeather}>
<input type = 'text' placeholder = 'Your city' ref="city"></input>
<input type = 'submit' placeholder='Submit' value = 'Submit'></input>
</form>
</div>
);
}
}
A form that runs a function on submit, I used preventDefault to stop the page from loading.
The function runs and the page doesn't reload. Now I'd like to grab the text from the input field and log it in that function. The reason why I want this is so I can use it in my API call as a query parameter. I tried many things. I tried logging e to see what is inside. It's a very big object and I couldn't find the value I'm looking for. I tried using ref, this didn't work either. Any idea how I could solve this issue?

You are using Uncontrolled Components.
You need to move your fetchWeather function inside of your component,
export default class App extends Component {
fetchWeather = (e) => {
e.preventDefault();
console.log(this.refs.city.value)//You will get vlue here
axios.get('https://api.openweathermap.org/data/2.5/weather?q=Zeist&appid=MYID')
.then(res => {
console.log(res.data);
});
console.log();
}
render() {
return (
<div>
<form onSubmit = {this.fetchWeather}> //refer your function using `this`
<input type = 'text' placeholder = 'Your city' ref="city"></input>
<input type = 'submit' placeholder='Submit' value = 'Submit'></input>
</form>
</div>
);
}
}
Better way is, using state. This is called Controlled Components.
export default class App extends Component {
state={
city: ''
}
handleChange = (e) => {
this.setState({[e.target.name]:e.target.value})
}
fetchWeather = (e) => {
e.preventDefault();
console.log(this.state.city)//You will get vlue here
axios.get('https://api.openweathermap.org/data/2.5/weather?q=Zeist&appid=MYID')
.then(res => {
console.log(res.data);
});
console.log();
}
render() {
return (
<div>
<form onSubmit = {this.fetchWeather}> //refer your function using `this`
<input type = 'text' placeholder = 'Your city' name="city" value={this.state.city} onChange={this.handleChange} ></input>
<input type = 'submit' placeholder='Submit' value = 'Submit'></input>
</form>
</div>
);
}
}

You can use a controlled component: https://reactjs.org/docs/forms.html.
I simulated the fetch operation in the snippet.
const fetchWeather = function (data) {
// simulating fetch
setTimeout(function() {
console.log('GETTING DATA ' + JSON.stringify(data))
}, 500)
}
// Controlled Component: https://reactjs.org/docs/forms.html
class App extends React.PureComponent {
constructor(props) {
super(props)
this.state = {
city: ''
}
this._handleInputChange = this._handleInputChange.bind(this)
this._handleSubmit = this._handleSubmit.bind(this)
}
_handleInputChange (event) {
const { value, name } = event.target
this.setState({
[name]: value
})
}
_handleSubmit (event) {
event.preventDefault()
fetchWeather(this.state)
}
render() {
const { city } = this.state
return (
<div>
<form onSubmit={this._handleSubmit}>
<input
type='text'
name='city'
placeholder='Your city'
value={city}
onChange={this._handleInputChange}
/>
<input type='submit' placeholder='Submit' value='Submit' />
</form>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('react')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Related

How to pass props through Link method in React?

I am trying to pass a prop from one component in which I search for and select a game to another component where I will render the details of the selected game. I am keeping my components as two separate pages, but I am struggling to get anything passing down to the child component. Here are my two files, and I have no idea where I am going wrong.
import React, { Component } from "react";
import Selected from "./Selected";
import { Link } from 'react-router-dom';
class Search extends Component {
constructor(props) {
super(props);
this.state = {
/*
API request format:
GET https://api.rawg.io/api/platforms?key=YOUR_API_KEY
GET https://api.rawg.io/api/games?key=YOUR_API_KEY&dates=2019-09-01,2019-09-30&platforms=18,1,7
Docs: https://api.rawg.io/docs
*/
baseURL: "https://api.rawg.io/api/games?",
apiKey: `key=${process.env.REACT_APP_RAWG_API_KEY}&`,
gamesQuery: "search=",
searchInput: "",
// later on we can determine whether to add additional parameters like page size, genres, etc.
searchURL: "",
gallery : [],
selectedGame: [],
};
}
handleChange = (event) => {
this.setState({
// we're grabbing the element or elements and dynamically setting the input value to the key corresponding to the input id of the same name in this.state
[event.target.id]: event.target.value,
});
};
handleSubmit = (event) => {
// keep the page from refreshing on submit
event.preventDefault();
this.setState(
{
// builds out our search url from the pieces we've assembled
searchURL:
this.state.baseURL +
this.state.apiKey +
this.state.gamesQuery +
this.state.searchInput,
},
() => {
// we fetch the url from the api
fetch(this.state.searchURL)
// .then waits till the fetch is complete
.then((response) => {
return response.json();
})
.then(
(json) => this.setState({
gallery : json.results
}),
(err) => console.log(err)
);
}
);
};
handleInspect = (event) => {
for (let i in this.state.gallery) {
if (i.id === event.id) {
this.setState ({
selectedGame : i
})
}
}
}
render() {
let game;
if (this.state.selectedGame) {
game = this.state.selectedGame
}
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>Search</label>
<input
id="searchInput"
type="text"
placeholder="What's the Name of the Game"
value={this.state.searchInput}
onChange={this.handleChange}
/>
<input type="submit" value="Find Games" />
</form>
<div id='gallery'>
{this.state.gallery.map(function(d, idx){
return (
<li key={idx}>
<a href={"/selected/"+d.id}
onClick={()=>this.handleInspect(d.id)}
>{d.name}</a>,
{d.id},
<Link to={{pathname: `/selected/${d.id}`,
gameResults : game}} />,
</li>)})}
</div>
</div>
);
}
}
export default Search;
And the component I try to pass to and fails.
import React from 'react';
import { Link } from 'react-router-dom';
class Selected extends React.Component {
render() {
{console.log(this.props)}
return (
<h1>woo</h1>
);
}};
export default Selected;
The result is below, with no props having been passed at all

How to change the state in react with a form

I have a form that is supposed to update the initial state, I've followed many tutorials and my code looks the same as them but for some reason it doesn't update the state.
import React, { Component } from 'react';
class Create extends Component{
constructor(props){
super(props);
this.state = {
title: "",
body: "",
error: ""
}
}
onTitleChange(e) {
const title = e.target.value;
this.setState({title})
}
onBodyChange(e) {
const body = e.target.value;
this.setState({body})
}
onSubmit(e) {
e.preventDefault();
if(!this.state.title || !this.state.body){
this.setState(() => ({ error: "Please fill in all gaps"}))
} else {
this.setState(() => ({ error: "" }))
// Send info to the main page
alert(this.state.title);
}
}
render(){
return(
<div>
{this.state.error && <p>{this.state.error}</p>}
<form onSubmit = {this.onSubmit}>
<label>Put a title for your note</label>
<input
placeholder="Title"
type="text"
value={this.state.title}
autoFocus
onChange= {this.onTitleChange}
/>
<label>Write your note</label>
<textarea
placeholder="Note"
value={this.state.body}
autoFocus
onChange = {this.onBodyChange}
/>
<input type="submit" value="Submit"/>
</form>
</div>
);
}
}
export default Create;
When I check the current state in the React developer tools it shows that the state remains the same and I don't know why because there are not errors in the log.
I'm working with webpack, babel and react.
////////////////////
EDITED
////////////////////
I edited my code following the suggestions you guys gave me but still it doesn't work. An alert is supposed to appear when submitted the form but that doesn't get fired either, so I believe that non of the functions are getting fired.
This is my edited code:
import React, { Component } from 'react';
class Create extends Component{
constructor(props){
super(props);
this.onTitleChange = this.onTitleChange.bind(this);
this.onBodyChange = this.onBodyChange.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
title: "",
body: "",
error: ""
}
}
onTitleChange(e) {
const title = e.target.value;
this.setState((prevState) => {
return {
...prevState,
title
};
});
}
onBodyChange(e) {
const body = e.target.value;
this.setState((prevState) => {
return {
...prevState,
body
};
});
}
onSubmit(e) {
e.preventDefault();
if(!this.state.title || !this.state.body){
this.setState((prevState) => {
return {
...prevState,
error: "Please fill in all gaps"
};
});
} else {
this.setState((prevState) => {
return {
...prevState,
error: ""
};
});
// Send info to the main page
alert(this.state.title);
}
}
render(){
return(
<div>
{this.state.error && <p>{this.state.error}</p>}
<form onSubmit = {this.onSubmit}>
<label>Put a title for your note</label>
<input
placeholder="Title"
type="text"
value={this.state.title}
autoFocus
onChange= {this.onTitleChange}
/>
<label>Write your note</label>
<textarea
placeholder="Note"
value={this.state.body}
autoFocus
onChange = {this.onBodyChange}
/>
<input type="submit" value="Submit"/>
</form>
</div>
);
}
}
export default Create;
You should try binding the event handlers in the constructor, because it seems like this within those event handling functions could be undefined. The React documentation outlines why the binding is necessary, and here's another useful page on handling forms in React.
constructor(props) {
super(props);
...
this.onTitleChange = this.onTitleChange.bind(this);
this.onBodyChange = this.onBodyChange.bind(this);
this.onSubmitChange = this.onSubmitChange.bind(this);
}
An alternative to binding in the constructor would also be to use arrow functions for your event handlers which implicitly bind this.
class Create extends Component {
...
onTitleChange = () => { ... }
onBodyChange = () => { ... }
onSubmitChange = () => { ... }
}
EDIT: Can't comment on your post since my reputation is too low, but it seems like there's a typo in the changes you just made.
this.onSubmitC = this.onSubmit.bind(this) should be changed to
this.onSubmit = this.onSubmit.bind(this)
React's setState() accepts an object, not a function. So change your onSubmit() to this:
if(!this.state.title || !this.state.body){
this.setState({ error: "Please fill in all gaps"})
} else {
this.setState({ error: "" })
// Send info to the main page
alert(this.state.title);
}
It better to use the previous state and only update the required (input value) values.
in your case you are replacing the existing state (whole object) just with the title and the same goes for body onBodyChange
onTitleChange () {
const title = e.target.value;
this.setState((prevState) => {
return {
...prevState,
title
};
});
};
<

React input and state cannot override

started learning react. I've been sitting on this problem for an hour and I have no idea why this is not working. Looking everywhere, but without any results. Am I dumb or what?
I cannot write in input field or when I can (if I fix it) then my state doesn't change. Maybe someone knows why is that a problem?
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
text: "test"
}
}
textChangedHandler = (event) => {
this.setState = ({
text: event.target.value
});
}
render() {
return (
<div className="App">
<p>{this.state.text}</p>
<input
type="text"
onChange={this.textChangedHandler}
value={this.state.text}>
</input>
</div>
);
}
}
export default App;
see your textChangedHandler
textChangedHandler = (event) => {
this.setState = ({
text: event.target.value
});
}
In this,
you need to set state like this.
this.setState({
text: event.target.value
})
this.setState is a method. You should need to reassign it.
textChangedHandler = (event) => {
this.setState({
text: event.target.value
});
}
render() {
return (
<div className="App">
<p>{this.state.text}</p>
<input
type="text"
onChange={this.textChangedHandler}
value={this.state.text}>
</input>
</div>
);
}
try this.
Try this one:
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
text: "test"
}
// This binding is necessary to make `this` work in the callback
this.textChangedHandler = this.textChangedHandler.bind(this)
}
textChangedHandler = (event) => {
this.setState({
text: event.target.value
});
}
render() {
return (
<div className="App">
<p>{this.state.text}</p>
<input
type="text"
onChange={this.textChangedHandler}
value={this.state.text}>
</input>
</div>
);
}
}
export default App;
More information: https://reactjs.org/docs/handling-events.html

React update input value on button click

I have a React component with an input field.
I want to update the value of the input field when a button is clicked, I can confirm that the value changes when I inspect element but it doesn't display in the input field. Below is a sample code to just to give an idea.
class InputField {
constructor(props) {
super(props)
}
state = {
userInput: ''
}
}
onClick = () => {
this.setState({
userInput: 'Test'
})
}
render() {
return ( <input value={this.state.userInput} name="sampleInput" />
<button onClick={this.onClick}> Click me </button>
)
}
Fix syntax
your code is ok, just little order.
I add the whole component
import React, { Component } from 'react';
class InputField extends Component {
constructor(props) {
super(props)
}
state = {
userInput: ''
}
onClick = () => {
this.setState({
userInput: 'Test'
})
}
render() {
return (
<div>
<input value={this.state.userInput} name="sampleInput" />
<button onClick={this.onClick}>Click me</button>
</div>
)
}
}
export default InputField;
I just removed syntax error in your example and it worked for me.
import React from 'react';
export default class InputField extends React.Component {
constructor(props) {
super(props)
this.state = {
userInput: ''
}
}
onClick = () => {
this.setState({
userInput: 'Test'
})
}
render() {
return (
<div>
<input value={this.state.userInput} name="sampleInput"/>
<button
onClick = {this.onClick}
>
Click me
</button>
</div>
)
}
}
One approach would be to implement this as a functional component via hooks. You could for instance use the state hook to store and render the userInput data as shown below:
import React from "react";
/* Declare functional InputField component */
function InputField () {
/* Define local state hook to store the "user input" data */
const [userInput, setUserInput] = React.useState("");
const onClick = (e) => {
/* Prevent button click's default behavior */
e.preventDefault();
/* Call the state's "setter" method to update "userInput" state */
setUserInput('Test')
}
/* Render both input and button in a <> fragment */
return (<>
<input value={this.state.userInput} name="sampleInput"/>
<button onClick={onClick}>Click me</button>
</>)
}
To use this component, simply render it as:
<InputField />
I just fix your syntax errors and it run no any error
class InputField extends React.Component {
constructor(props) {
super(props);
this.state = {
userInput: '',
};
}
onClick = () => {
this.setState({
userInput: 'Test',
});
};
render() {
return (
<div>
<input value={this.state.userInput} name="sampleInput" />
<button onClick={this.onClick}>Click me</button>
</div>
);
}
}

Can't get the actual value of a input in react

I was developing a react component to get a value inside a input and automatically show it in a tag, using refs.
All works fine, but the value shown is the previous value.
I really don't now how to fix this. I using the onChange event in the input to change the state of what will be shown, it is clear that the present value is not taken, but rather the previous value
class Conversor extends Component {
constructor(props){
super(props)
this.state = {
value: null
}
this.output = this.output.bind(this)
}
output(){
console.log(this.state)
this.refs.output.innerHTML = this.state.value
}
render() {
return (
<div>
<h2>{this.state.inputValue}</h2>
<input ref="input" type="text" onChange={() => {this.setState({ value: this.refs.input.value }); this.output()}}/>
<label ref="output"></label>
</div>
);
}
}
If i put the value "Hello World" in the input, the value shown is "Hello Worl", when it's have to be the "Hello World"
You can use event to do this and no need of output() function.
class Conversor extends Component {
constructor(props){
super(props)
this.state = {
value: null
}
}
render() {
return (
<div>
<h2>{this.state.inputValue}</h2>
<input ref="input" type="text" onChange={(e) => {this.setState({ value: e.target.value });}}/>
<label ref="output">{this.state.value}</label>
</div>
);
}
}
The best way to achieve your goal is not using the refs. Here is how you do it
class Conversor extends Component {
constructor(props){
super(props)
this.state = {};
}
handleChange = (e) => {
const { id, value } = e.target;
this.setState({
[id]: value
})
}
render() {
const { name, anotherName } = this.state;
return (
<div>
<h2>{name}</h2>
<input id="name" name="name" type="text" onChange={this.handleChange}/>
<h2>{anotherName}</h2>
<input id="anotherName" name="anotherName" type="text" onChange={this.handleChange}/>
</div>
);
}
}
If you still want to use the refs then do the following,
class Conversor extends Component {
constructor(props){
super(props)
this.state = {
value: null
}
}
output = (e) =>{
this.setState({value: e.target.value }, () => {
this.refs.output.innerHTML = this.state.value
})
}
render() {
return (
<div>
<input ref="input" type="text" onChange={this.output}/>
<label ref="output"></label>
</div>
);
}
}
You don't need to bind your input handler function at all. Instead of doing that, just use an arrow function like _handleInputTextChange . Check this out:
import React, { Component } from 'react';
class InputTextHandler extends Component {
constructor(props){
super(props)
this.state = {
inputValue: ''
}
}
_handleInputTextChange = e => {
const inputValue = e.target.value;
this.setState({inputValue})
console.log(inputValue)
}
render() {
return (
<div>
<input
type="text"
onChange={this._handleInputTextChange}/>
</div>
);
}
}
export default InputTextHandler;
Two things: grab the event value in the onChange method, and pass the this.output method as the second argument to setState which fires after the state has been updated which is not a synchronous operation.
render() {
return (
<div>
<h2>{this.state.inputValue}</h2>
<input ref="input" type="text" onChange={event => {this.setState({ value:event.target.value }, this.output)}}/>
<label ref="output"></label>
</div>
);
}
Try it here!

Categories