what am i doing wrong with ReactJS eventHandlers - reactjs

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;

Related

Squaring the value of an input box in React

I am new to learning React and doing a little test project each day. Today, I am trying to create an input box that when I click a Submit button, it alerts the square of a number. Nice and simple. But, I am trying to do this without using State. Just trying to understand how. Here is my code but something is missing. I think I am close!
Any ideas?
import { render } from '#testing-library/react';
import React from 'react';
class App extends React.Component {
sayHi = props => {
alert(this.props.mySentProps);
};
squareTheNumber = () => {
alert('this is the squared number'+ );
};
render() {
return (
<div>
<div onClick={this.sayHi}>
<h1>Hello World</h1>
</div>
<div>
<input type="text" placeholder={'Enter a number to square'} />
</div>
<div>
<button onClick={this.squareTheNumber}>Submit me</button>
</div>
</div>
);
}
}
export default App;
Try this:
import React from "react";
import "./styles.css";
class App extends React.Component {
sayHi = (props) => {
alert(this.props.mySentProps);
};
squareTheNumber = (event) => {
event.preventDefault();
// Should be the same as input's "name" or "id" property
// Docs: https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements
const { number } = event.target.elements;
alert(`this is the squared number: ${number.value ** 2}`);
};
render() {
return (
<div>
<div onClick={this.sayHi}>
<h1>Hello World</h1>
</div>
<div>
<form onSubmit={this.squareTheNumber}>
<input
name="number"
type="text"
placeholder="Enter a number to square"
/>
<button type="submit">Submit me</button>
</form>
</div>
<div></div>
</div>
);
}
}
export default App;
P.S.: render from #testing-library/react is used for testing purposes only. See docs here. Class components have their own field with the same name.
As said, there is no clean way to do it without state or any extensions. The best way is to use state and make things clean. But another way you can do it is to use JQuery.
For example:
You can assign the <input> an id, say myId. Then you do this:
var content = $('#myId').content;
And then you can change the content in the p by assigning it a new value.
But using JQuery kinds of defeats the purpose of React, so I would recommend using state.
You can use refs to access mounted elements directly.
https://reactjs.org/docs/refs-and-the-dom.html

Get value from input component and use it in another component in React

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

How to check whether React updates dom or not?

I wanted to check how to react does reconciliation so I updated the inner HTML of id with the same text. Ideally, it shouldn't update the dom but it is paint reflashing in chrome.
I have tried paint reflashing in chrome it is showing green rectangle over that same text
import React from 'react';
function App() {
return (
<div >
<p id="abc" key="help">abc is here</p>
<button onClick={function () {
// document.getElementById("may").innerHTML = "";
document.getElementById("abc").innerHTML = "abc is here";
}} > Btn</button>
</div>
);
}
export default App;
Expected result should be that paint reflashing shouldn't happen but it is happening.
You are not using React here to update the text of your p tag but directly updating the DOM with JavaScript.
So React reconciliation algorithm doesn't even run here.
In React, the output HTML is a result of the state and the props of your component.
When a change in state or props is detected, React runs the render method to check if it needs to update the DOM. So, in order to do this check, you need to store the parameters that determine your view in state or props.
Given your example, we could save the text you want to show in the p tag in the state of your component (using hooks):
import React, { useState } from 'react';
function App () {
const [text, setText] = useState('abc is here');
render() {
return (
<div >
<p id="abc" key="help">{this.state.text}</p>
<button onClick={() => setText('abc is here') }>Btn</button>
</div>
);
}
}
export default App;
If you are using a version of React that does not support hooks, you will need to transform your functional component into a class to use state:
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = { text: 'abc is here' };
}
render() {
return (
<div >
<p id="abc" key="help">{this.state.text}</p>
<button onClick={() => this.setState({ text: 'abc is here' }) }>Btn</button>
</div>
);
}
}
export default App;

Material Components Web and React: Cannot read property 'querySelector' of undefined;

I am trying to build a Modal component taking advantage of React and Material Components Web. The visibility of Modal is inherited from the parent state as props:
import React, {Component} from 'react';
import {MDCFormField} from '#material/form-field/';
import {MDCTextfield} from '#material/textfield/';
import './modal.scss';
export default class Modal extends Component {
componentDidMount() {
this.email = new MDCTextfield(this.email);
this.pwd = new MDCTextfield(this.pwd);
}
componentWillUnmount() {
this.email.destroy();
this.pwd.destroy();
}
render() {
if (this.props.isModalOpen){
return (
<div id="modal-container">
<div id="mask"></div>
<div id="modal">
<form className="mdc-form-field">
<div ref={(div) => {this.email = div}} className="mdc-textfield">
<label type="email" htmlFor="email" className="mdc-textfield__label">Your email</label>
<input type="text" id="email" className="mdc-textfield__input"/>
<div className="mdc-textfield__bottom-line"></div>
</div>
<div ref={(div) => {this.pwd = div}} className="mdc-textfield">
<label htmlFor="pw" className="mdc-textfield__label">Password</label>
<input type="password" id="pw" className="mdc-textfield__input" required minLength={8}/>
<div className="mdc-textfield__bottom-line"></div>
</div>
</form>
</div>
</div>
);
} else {
return null
}
}
}
As soon as the app initialise an error appears "TypeError: Cannot read property 'querySelector' of undefined”
Of course it does since the since as the Modal is returning null.
so i tried to initialise Material Components as
componentDidMount() {
this.email = this.email && new MDCTextfield(this.email);
this.pwd = this.pwd && new MDCTextfield(this.pwd);
}
In this case the error is not thrown anymore but obviously the components are not initialised.
I did not come up with a pattern to solve this problem. Also a css approach did not work ( the idea was to toggle .someClass {display: none} from the main container ).
/** SOLVED **/
Ok I came up with a working pattern to solve the problem.
The problem was in the architecture of the app and the encapsulation of the components was not appropriate.
This is a parent component called Modal:
import React, {Component} from 'react';
import EmailField from './email-field';
import PwdField from './password-field';
import './modal.scss';
export default class Modal extends Component {
render() {
if (this.props.isModalOpen){
return (
<div id="modal-container">
<div id="mask"></div>
<div id="modal">
<form className="mdc-form-field">
<EmailField />
<PwdField />
</form>
</div>
</div>
);
} else {
return null
}
}
}
Than we have Children components as
import React, {Component} from 'react'
import {MDCTextfield} from '#material/textfield/';
export default class EmailField extends Component {
componentDidMount(){
this.email = new MDCTextfield(this.email);
}
componentWillUnmount(){
this.email.destroy();
}
render(){
return(
<div ref={(div) => {this.email = div}} className="mdc-textfield">
<label type="email" htmlFor="email" className="mdc-textfield__label">Your email</label>
<input type="text" id="email" className="mdc-textfield__input"/>
<div className="mdc-textfield__bottom-line"></div>
</div>
);
}
}
I was trying to init and destroy from a different scope of MDCTextfield elements.
You should try out the react version of this library.
Try to console.log(this.email). Afterwards you will see, that ref that you try to pass is not a selector, this is expected when you initialise matertial-components.
#Fawaz answer is correct, but you can instantiate it the way you want, even on div.
Showcase: https://www.webpackbin.com/bins/-KwEsyJR3O3eW50gX2pq
Did you using components like i am using there?
Use this for reference:
Material Components Textfield, Manual Instantiation

React Webpack - Submit Button not retrieving input value on form submit

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

Resources