I'm using webpack with React and I can't for the life of me understand what is going on in this build. This is what's supposed to be happening.
The var headerInput changes to whatever value is inputted onChange.
When the form is submitted(onSubmit) the console.log logs the headerInput value.
The problem: The value that gets console logged is numerical, it's usually something like: .0.0.1. I think it's console.log'ing the click event. Why isn't the value being assigned like in the in the handlerInput function?
Any help is much appreciated.
Thanks, All.
var headerInput = null;
import React from "react";
export default class Navigation extends React.Component{
handlerInput(e,headerInput){
headerInput = e.target.value;
console.log(headerInput);
};
clickSubmit(e,headerInput){
e.preventDefault();
console.log(headerInput);
};
render(){
return(
<form onSubmit={this.clickSubmit.bind(this)}>
<input type="text" placeholder="change header" onChange={this.handlerInput.bind(this)} />
<button>Change Header</button>
</form>
);
}
};
This is not the recommended way to be using React. Instead of relying on a "global" to store your state, you should be using the state API that come with components.
Like so:
import React from "react";
export default class Navigation extends React.Component{
constructor(props) {
super(props);
// Set up your default state here.
this.state = { };
// Do early binding.
this.handlerInput = this.handlerInput.bind(this);
this.clickSubmit = this.clickSubmit.bind(this);
}
handlerInput(e){
// Use setState to update the state.
this.setState({
headerInput: e.target.value
}
};
clickSubmit(e){
e.preventDefault();
// You read state via this.state
console.log(this.state.headerInput);
};
render(){
return(
<form onSubmit={this.clickSubmit}>
/* Make sure you pass the current state to the input */
<input
type="text"
placeholder="change header"
onChange={this.handlerInput}
value={this.state.headerInput}
/>
<button>Change Header</button>
</form>
);
}
};
I definitely recommend you revisit the official react docs, like the thinking in react and react forms tutorials.
If the input is strictly one-way (you only read from it) then just use a ref
import React from "react";
class Navigation extends React.Component{
clickSubmit(e,headerInput){
e.preventDefault();
console.log(this.inputEl.value);
};
render(){
return(
<form onSubmit={this.clickSubmit.bind(this)}>
<input placeholder="change header" ref={el => this.inputEl = el} />
<button>Change Header</button>
</form>
);
}
};
Note that...
Although string refs are not deprecated, they are considered legacy,
and will likely be deprecated at some point in the future. Callback
refs are preferred.
https://facebook.github.io/react/docs/more-about-refs.html
Related
I'm new to React and have this simple code example where I simply need to take value from input and show the value back.
class App extends React.Component {
constructor(props){
super(props);
this.state = { word : ""};
this.onClick = this.onClick.bind(this);
}
onClick(e){
this.setState({word : /* how to obtain input value?? */});
}
render() {
return (
<>
<form>
<input type="text"/>
<button onClick={this.onClick}>Say it!</button>
</form>
<div>
{this.state.word}
</div>
</>
);
}
}
I know react want's me to use component state as a way to propagate information from parent component to it's children. What I don't know is how I should obtain state of a children to be used in another children.
I believe this should be doable in react in simple manner as the equivalent way of doing it using pure DOM or JQuery would also be very simple (one or two lines of code).
You can use createRef
import React, { createRef } from "react";
import "./styles.css";
class App extends React.Component {
constructor(props) {
super(props);
this.state = { word: "" };
this.onClick = this.onClick.bind(this);
}
textInput = createRef();
onClick(e) {
this.setState({ word: this.textInput.current.value });
}
render() {
return (
<div className="App">
<form>
<input ref={this.textInput} type="text" />
<button onClick={this.onClick} type="button">
Say it!
</button>
</form>
<div>{this.state.word}</div>
</div>
);
}
}
export default App;
check here CodeSandBox
A few things here. First I don't see children as you mention. Moreover, you say obtain state of a children to be used in another children. You have just one parent component here. Then, you are using a <form> which means a button inside will submit the values so you need the escape hatch of e.preventDefault(). Finally, if you must use a class based component instead of functional component, you don't need any more constructor and you can bind your functions with an arrow function. Here is a working example of what I presume you are asking: https://codesandbox.io/s/sleepy-minsky-giyhk
I understand that this question has been asked many different times. I've looked through many different ones and I'm still having a difficult time understanding it.
I've read many articles online and I know that I need to pass my state to props and I'm having a difficult time doing so. I managed to pass a simple string of test, however I cannot pass my state to props as it simply returns nothing and I'm not sure why if the values on the form get updated in the onchange method.
I also want to avoid using redux as a alternative as I'm trying to learn the basic way first
What I'm trying to do is very simple, user fills out a box that contains ordernumber on the form. They hit submit, redirects to another page where I'll have access to the ordernum they submitted on the input box for the order number.
Here is my code:
simple input form page
/*eslint-disable no-unused-vars*/
import React from 'react';
import ReactDOM from 'react-dom';
class Reloform extends React.Component {
constructor(props){
super(props);
this.state = {
orderNum: "",
errorMsg: ""
}
}
onChange(e){
this.setState({
[e.target.name]: e.target.value
})
}
onSubmit(e){
if(this.state.orderNum === '') {
this.setState({
errorMsg: 'Please enter your order number.'
});
} else {
this.setState({
errorMsg: ''
});
// Submission successful
window.location = '/relotoForm';
}
e.preventDefault();
}
render() {
console.log(this.props)
return (
<div className="container">
// I get message prop back but not orderNum?
<h1>{this.props.message}</h1>
<h1>{this.props.orderNum}</h1>
<div className="reloContainer">
<form
method="POST"
id="reloForm"
onSubmit={e => this.onSubmit(e)}
autoComplete="off"
>
<h1>T/O Form</h1>
{this.state.errorMsg !== '' ? <p style={{color:'#E2231A'}}>Please enter an order number.</p> : ''}
<label>Order #</label>
<input
type="text"
name="orderNum"
className="form-control"
value={this.state.orderNum}
onChange={e => this.onChange(e)}
/>
<button type="submit" className="btn btn primary" id="reloButton" onClick={this.props.updateData}>Submit</button>
</form>
</div>
</div>
)
}
}
export default Reloform;
/* form action page */
/*eslint-disable no-unused-vars*/
import React from 'react';
import ReactDOM from 'react-dom';
import Reloform from './reloForm';
class Relotoform extends React.Component {
render() {
return (
<div>
//The string that I returned works but the state that I try to have access on this page does not. I am not sure why. My assumption is because maybe this.state is referring to the state of this component and not the form component on my form page?
<Reloform message="Works" orderNum={this.state.orderNum} />
</div>
)
}
}
export default Relotoform;
State is local to the component you are accessing. If you want to pass a state value to another component, this is where you use props. So when you are trying to render Reloform in your Relotoform component, when you do orderNum={this.state.orderNum}, you won't get any value as there is no state defined for Relotoform in which there's a variable called orderNum.
You need to update the orderNum through your state in the Reloform. You get message displayed because you are passing the value "Works" as a prop in Relotoform. Then you are accessing it correctly as a prop in Reloform. Adapt a similar arhcitecture for orderNum.
I'm trying to make suggested search entries display in from Google Api appear in the div with the id Suggested-Places using input values from the input tag with the id SearchBar. Unfortunately,the event handlers aren't firing.
here is my code
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import logo from './logo.svg';
import './App.css';
import MdShoppingCart from 'react-icons/lib/md/shopping-cart'
export default class HeaderMin extends Component{
constructor(props) {
super(props);
this.suggestedPlaces=[];
this.state={
suggestions:this.suggestedPlaces
}
this.userLocationInput=this.userLocationInput.bind(this);
this.suggestedLocations=this.suggestedLocations.bind(this);
}
componentDidMount() {
this.address=this.refs.inputBox.value;
const searchBar=ReactDOM.findDOMNode(this.refs.inputBox);
searchBar.addEventListener('keyUp keyPress keyDown',this.userLocationInput)
}
suggestedLocations(location){
this.suggestedPlaces.push(location);
}
userLocationInput() {
const key="&key=AIzaSyCvfy3g8ljGFtVyfCP9idWbwRo_-HASt_0",url="https://maps.googleapis.com/maps/api/place/textsearch/json?query=";
let query=this.address;
const endPoint=url+query+key;
return fetch("http://localhost:8080/"+url+query+key)
.then((res)=>res.json())
.then((res)=>res.results.map((loc)=>this.suggestedLocations(loc.formatted_address)))
}
render(){
return(
<div className="myheader header-min">
<img src="http://res.cloudinary.com/www-mybukka-com/image/upload/v1505151382/logo_m8ik1x.png" id="logo" alt="logo"/>
<div className="search-box search-box-min">
<div>
<input type='text' ref="inputBox" id="SearchBar" defaultValue='search your location'/>
<div id="Suggested-Places">{this.state.suggestions.map((location)=><p>{location}</p>)}</div>
</div>
<button className="btn-sml btn-red"></button>
</div>
<div className="header-top-button header-top-button-min">
<button ></button>
<button className="btn-red"></button>
<MdShoppingCart className="shopping-cart"/>
</div>
</div>
)
}
}
React use synthetic events, so your regular events won't probably work. Use the regular React way if you want it to work.
You should be using Reacts built-in event handler props. Also, you can simplify your code:
<input type='text' ref="inputBox" id="SearchBar" defaultValue='search your location' onKeyDown={this.userLocationInput}/>
You probably don't need to bind the same event to all 3 key events, onKeyDown should be enough. If you need the other ones as well, you can use onKeyPress and onKeyUp.
EDIT:
And after looking at userLocationInput, you'll need to make a small change:
userLocationInput(e) {
const key="&key=AIzaSyCvfy3g8ljGFtVyfCP9idWbwRo_-HASt_0",url="https://maps.googleapis.com/maps/api/place/textsearch/json?query=";
let query = e.target.value; // or this.refs.textInput.value
const endPoint=url+query+key;
return fetch("http://localhost:8080/"+url+query+key)
.then((res)=>res.json())
.then((res)=>res.results.map((loc)=>this.suggestedLocations(loc.formatted_address)))
}
When you bind this.address in the componentDidMount to this.refs.textInput.value, that's a one time assignment. this.address won't update everytime the value gets changed. So instead you should be using e.target.value or this.refs.textInput.value.
One last note, string refs are being deprecated in React so you should be using a ref callback instead.
<input ref={ ref => this.textInput = ref } />
...
// Getting value from input
this.textInput.value;
as the link https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute
It then only gives an example of using the component immediately. I'm trying to find out how i would use this function to access the component immediately, and save the component for future use, as it says we are able to do.
The difference is using ref={callback} react passes the responsibility of managing the reference storage back to you. When you use ref="sometext", under the covers react has to create a refs property on your class and then add all the ref="sometext" statements to it.
While its nice to have a simple this.refs.sometext access to components its difficult and error prone on the react side to clean up this refs property when the component is destroyed. It's much easier for react to pass you the component and let you handle storing it or not.
According to the react docs
React will call the ref callback with the DOM element when the
component mounts, and call it with null when it unmounts.
This is actually a pretty slick idea, by passing null on unmount and calling your callback again you automatically clean up references.
To actually use it all you have to do is access it from any function like so:
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.focus = this.focus.bind(this);
}
focus() {
// Explicitly focus the text input using the raw DOM API
this.textInput.focus();
}
render() {
// Use the `ref` callback to store a reference to the text input DOM
// element in this.textInput.
return (
<div>
<input
type="text"
ref={(input) => { this.textInput = input; }} />
<input
type="button"
value="Focus the text input"
onClick={this.focus}
/>
</div>
);
}
}
The callback you set on ref will receive the component as the first parameter, the 'this' word will be the current class 'CustomTextInput' in this example. Setting this.textInput in your callback will make textInput available to all other functions like focus()
Concrete Example
Tweet from Dan Abermov showing a case where ref callbacks work better
Update
Per Facebook Docs using strings for refs is consider legacy and they "recommend using either the callback pattern or the createRef API instead."
When you assign a ref={callback} like <input type="text" ref={(input) => {this.textInput = input}}/> what basically you are doing is saving the ref with the name textInput for future use. So instead of using ref="myInput" and then using this.refs.myInput we can use the call back bethod and then access the component later like this.textInput.
Here is a demo for the same, whereby we are accessing the input value using ref on button click
class App extends React.Component {
constructor(){
super();
}
handleClick = () => {
console.log(this.textInput.value);
}
render() {
return (
<div>
<input type="text" ref={(input) => {this.textInput = input}}/>
<button type="button" onClick={this.handleClick}>Click</button>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.4/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.4/react-dom.min.js"></script>
<div id="app"></div>
With React 16.3, you can use React.createRef() API instead:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={this.myRef} />;
}
}
React newb here. I have a pure function that returns a form (presentation component). In this form I need to handle onChange events for those text fields that are controlled. FWIU, I need to this.setState(...) in my onChange event handlers. However due to this being a pure function, I don't have access to this.setState(). Is there a nice way to set the state on these onChange events in a ES2015 function? I'm also using redux if this helps. Example code:
import React, {PropTypes} from 'react'
const ApplicationForm = ({submitHandler, person}) => (
<form onSubmit={e => submitHandler(e)}>
<div>
<label htmlFor="firstName">First Name:</label>
<input type="text" name="firstName" onChange={e => setState(e.target.value)} value={person.firstName || ''}/>
</div>
...
</form>
)
That is a Stateless Function, there is no state to set
If you're using redux, you probably want to trigger a redux action in the onChange, passing the new value as an argument, and have the action update the value of firstName in the redux store for person.firstName
I would recommend taking a look at redux-form to reduce a bunch of boilerplate
You can actually use setState in something that looks like a functional component, but it's pretty hacky. I imagine this method is something only people who really can't stand using the this keyword and class syntax would ever use. Still, I think it's kind of fun.
Here's how you might write an input that changes another element in a normal way using this and class syntax:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {text: "Hello, world"};
}
handleChange = (event) => {
this.setState({text: event.target.value});
}
render() {
return (
<div>
<input value={this.state.text} onChange={this.handleChange} />
<h1>{this.state.text}</h1>
</div>
)
}
}
And here's how you could create the same effect without this and class syntax:
function App() {
"use strict";
const obj = {
state: {text: "Hello, world"},
__proto__: React.Component.prototype
};
obj.handleChange = function (event) {
obj.setState({text: event.target.value});
};
obj.render = function () {
return (
<div>
<input value={obj.state.text} onChange={obj.handleChange} />
<h1>{obj.state.text}</h1>
</div>
);
};
return obj;
}
The trick is to make the App function inherit from React.Component by setting the dunder proto property of the object App returns to React.Component's prototype so that it can use setState.
Here's a codepen if you want to play around with the code.
Stateless functional components can't have state... because they're stateless. If you want to have event handlers to call and state to set, you will need to create a component class, either via React.createClass or by using ES6 classes.
You can use react hooks to achieve what you want.
If you write a function component and you want to add some sate to your function, previously you had to change your function into a class. But now you can use react hooks to create your state in your functional component.
EX:- We write class components with state as below
class Foo extends Component {
constructor(props) {
super(props);
this.state = {
age: 20
};
}
now we can achieve above code in function component as followed
import React, { useState } from 'react';
function Foo() {
const [age, setAge] = useState(20);
Refer this document for more details - https://reactjs.org/docs/hooks-state.html
With React Hooks, we now have state usability extended to functional components as well.
To use this, we can import {useState} from React and pass default value into its arguments.
import React, {PropTypes, useState} from 'react'
const ApplicationForm = ({submitHandler, person}) => (
const [name, updateName]= useState(person.firstName);
<form onSubmit={e => submitHandler(e)}>
<div>`enter code here`
<label htmlFor="firstName">First Name:</label>
<input type="text" name="firstName" onChange={e => updateName(e.target.value)} value={name || ''}/>
</div>
...
</form>
)
More details about this can be found in the documentation for useState.