Error when trying to use useRef on a page [duplicate] - reactjs

This question already has an answer here:
React hook unable to be called inside of class component
(1 answer)
Closed 8 months ago.
I want to use useRef() and componentDidMount() to autofocus an input field on a page. Here's the page code:
import React, { Component, useState, useEffect } from "react";
import styles from '../..//styles/Home.module.css'
interface Props {
}
class Test extends Component<Props> {
nameRef = React.useRef<HTMLInputElement>(null);
componentDidMount() {
this.nameRef.current!.focus();
}
render() {
return (
<main className={styles.main}>
<form action="/account/sign-up" method="post">
<label htmlFor="last">Name:</label>
<input type="text" id="name" name="name" required ref={this.nameRef} />
<label htmlFor="first">Email address:</label>
<input type="text" id="email" name="email" required />
<button type="submit">Submit</button>
</form>
</main>
)
}
}
export default Test
However I get an error at runtime: Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This error is at the nameRef = React.useRef.. line.

You must not write hooks in class-based component. In order to use hooks you must rewrite your component to a functional component.
UPDATED
I misunderstood question and thats why my answer is probably not complete. If you wan to use refs with class based component you should use React.createRef() function.

Related

Declaring function inside class component in React

import React from 'react';
class App extends React.Component {
getTime() {
return new Date().toLocaleDateString();
}
state = { time: null };
render() {
return (
<div htmlFor="search">
<label className="search" htmlFor="username">Name Please: </label>
<input id="username" type="text" />
<button style={{backgroundColor: 'blue', color: 'white'}}> Submit </button>
<p>{getTime()}</p>
</div>
)
}
}
export default App;
I've been trying to get the time and display it in React but I keep getting errors.
Line 16:11: 'getTime' is not defined no-undef
But I've been doing just as tutorial told me to. What am I doing wrong?
first of all usually we define state in the beginning so just put it before getTime function
second thing - to be able to use functions in class components in react you have to add this before so just make it
<p>{this.getTime()}</p>
You should use this keyword for referring to the class and then methods and properties.
So this.getTime(); should be used.

hooks are not rendering in react

In react, I am trying to use react hooks.I have created one hook which contains a form and I am importing that in class based component and rendering it there. But hooks is not rendering in contact component
//contactushook.js
import React from 'react';
const contactUshook = props => {
return <React.Fragment>
<form>
<div>
<input id="name" type="text" placeholder="enter the name"></input>
</div>
<div>
<input id="email" type="email" placeholder="enter the email"></input>
</div>
<div>
<input id="message" type="text-area" placeholder="Type message here"></input>
</div>
<button type="submit">Submit</button>
</form>
</React.Fragment>
}
export default contactUshook;
//contact.js
import React, { Component } from 'react';
import contactUshook from './hooks/contactushook';
class ContactComponent extends Component {
render() {
return (
<div>
<h4>hook</h4>
<contactUshook></contactUshook>
</div>
);
}
}
export default ContactComponent;
Your code is pretty working. You've should name your custom component <contactUshook> starting with capital letter, so React knows that it is custom component and not html tag.
Note: Always start component names with a capital letter.
React treats components starting with lowercase letters as DOM tags. For example, represents an HTML div tag, but represents a component and requires Welcome to be in scope.
So this will fix you issue
import React, { Component } from 'react';
import ContactUshook from './hooks/contactushook';
class ContactComponent extends Component {
render() {
return (
<div>
<h4>hook</h4>
<ContactUshook></ContactUshook>
</div>
);
}
}
export default ContactComponent;
And as already mentioned, your code does not deal with hooks. You created ordinary components.
Working sample is here

React Auto RTL text inputs

I want all my components using input[type=text] to get RTL or LTR direction based on user input automatically.
Back in old days(2 or 3 years ago) I used jQuery to select all these inputs and apply my script like this. But what is the best solution to implement this feature in React?
build your wrapper around Input component and do your logic inside this component :) Then everywhere in the code use your <CustomInput /> instead <input ...>.
EDIT:
enclosing a code example of wrapping input element:
import React from "react";
class CustomInput extends React.Component {
render() {
const {onChange, ...otherProps} = this.props;
// Please provide onChange callback to make this Input element "Controlled"
// otherProps are there for things like default value etc. :)
return(
<input type="text" onChange={onChange} />
);
}
}
export default CustomInput;
and if you will not use any of the lifecycle methods you can even implement this component as a function
import React from "react";
const CustomInput = ({onChange, ...otherProps}) => (
<input type="text" onChange={onChange} />;
);
export default CustomInput;

React way to "setState" in a pure ES2015 function

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.

React bootstrap - Uncaught TypeError: Cannot read property 'toUpperCase' of undefined

My class is as follows:
import React from 'react';
import Input from 'react-bootstrap';
export default class FormWidget1 extends React.Component {
render() {
if (!this.props.fields) {
console.log('no fields passed');
}
else {
console.log(this.props.fields.length);
console.log(this.props.fields);
}
var formFieldList = this.props.fields.map(function(field) {
console.log("iterating");
return (
<Input type="text" placeholder="testing" label="label" />
);
});
return (
<div>
<form action="">
{formFieldList}
</form>
</div>
);
}
}
If I replace <Input /> with <input /> then there's no error.
The stacktrace only shows my app.jsx which is not useful.
What is wrong?
You need to de-structure your import of the Input jsx component.
import {Input} from 'react-bootstrap';
What this does is render to var Input = require('react-bootstrap').Input; Whereas what you previously had would render to var Input = require('react-bootstrap');
It does mention this in the documentation for React Bootstrap here:
https://react-bootstrap.github.io/getting-started.html#es6
Edit: A good hint is that the error you're getting from React is a typical error when you're trying to render as a component, something which is actually not a react component. So basically you were trying to render the object that react bootstrap returns containing all components, rather than the actual input component you wanted.

Resources