I am trying to select all the text in a textarea when a component loads using React v16.3.1
Following the Refs docs I have a basic sample but this.textarea is always undefined, if I change this sample to execute the same code on a button click it works fine.
So whats going on? I had expected that after mounting the component should be available?
Sample code:
import React from "react";
class Hello extends React.Component {
constructor(props) {
super(props);
this.textarea = React.createRef();
}
componentDidMount = () => {
this.textarea.current.select();
};
render() {
return (
<div>
<textarea
className="form-control"
defaultValue="the quick brown fox."
ref={this.textarea}
/>
</div>
);
}
}
From package.json:
"react": "^16.3.1",
"react-dom": "^16.3.1",
Thanks
The documentation says:
Note
The examples below have been updated to use the React.createRef() API
introduced in React 16.3. If you are using an earlier release of
React, we recommend using callback refs instead.
If you are using an earlier release of React, u need use callback refs
class App extends React.Component {
constructor(props) {
super(props);
this.textarea = null;
this.setTextareaRef = element => {
this.textarea = element;
};
}
componentDidMount = () => {
if (this.textarea) this.textarea.select();
};
render() {
return (
<div>
<textarea
className="form-control"
defaultValue="the quick brown fox."
ref={this.setTextareaRef}
/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Using React 16.3
class App extends React.Component {
constructor(props) {
super(props);
this.textarea = React.createRef();
}
componentDidMount = () => {
this.textarea.current.select();
};
render() {
return (
<div>
<textarea
className="form-control"
defaultValue="the quick brown fox."
ref={this.textarea}
/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://unpkg.com/react#16.3.1/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom#16.3.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Related
Style-1
Please Check both styles
import React, { Component, createRef } from 'react'
class Click extends Component {
buttonRef = createRef();
updatedValue = 0;
clickCounter = () => {
this.updatedValue = this.buttonRef.current.value++;
console.log("upDatedValue outside of render() method= "+ this.updatedValue)
}
render() {
console.log("upDatedValue inside of render() method= "+ this.updatedValue);
return (
<div>
<button ref={this.buttonRef} onClick={this.clickCounter}>
Clicked {this.updatedValue} Times</button>
</div>
)
}
}
export default Click
Style-2
import React, { Component, createRef } from 'react'
class Click extends Component {
buttonRef = createRef();
updatedValue = 0;
render() {
let clickCounter = () => {
this.updatedValue = this.buttonRef.current.value++;
console.log("upDatedValue inside of cliclCounter() method= "+ this.updatedValue);
}
console.log("upDatedValue inside of render() method= "+ this.updatedValue);
return (
<div>
<button ref={this.buttonRef} onClick={clickCounter}>
Clicked {this.updatedValue} Times</button>
</div>
)
}
}
export default Click
None of these approach is not working. It always show "Clicked 0 Times"
Can anyone please explain why this is not working and what the solution is.
Thank you.
-Samiul Fahad
You are not updating the state of your counter. Here's a solution, since you are using class based components:
class Click extends React.Component {
constructor(props) {
super(props);
this.state = {
updatedValue: 0
}
this.clickCounter = this.clickCounter.bind(this);
}
clickCounter(){
this.setState({updatedValue: this.state.updatedValue+1})
}
render() {
return (
<div>
<button onClick={this.clickCounter}>
Clicked {this.state.updatedValue} Times</button>
</div>
)
}
}
ReactDOM.render(<Click />, document.getElementById('root'));
<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>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
I'm tinkering with a React application where I have a Class component and a Functional Component. My Class component has a function for updating a name in its state. I'm trying to pass this function to a Functional Component as a property, the invocation works fine and I can see the argument making it into the method while debugging the application in a browser, but things blow up when trying to invoke this.setState, because 'this' is 'undefined'. I know about React hooks but don't think they are able to deal with a parent components state. Is there a technique for handling this kind of situation?
Note: the below snippets are pseudo code so just assume there's a button and clicking it works
The Class Component
class MyClassComponent extends React.Component {
constructor(props) {
super(props);
this.setName = this.setName.bind(this);
this.state = {
name: '',
};
}
setName(name) {
this.setState({
name: name
});
}
render() {
return (
<MyFunctionalComponent
setName={this.setName}/>
);
}
}
The Functional Component
export const MyFunctionalComponent = props => {
const { setName } = props;
return (
<button onClick={setName('fred')}>
);
};
The exception
Uncaught TypeError: Cannot read property 'setState' of undefined
The issue in your code is in MyFunctionalComponent component. you are calling the setName function on component render.
Try this.
export const MyFunctionalComponent = props => {
const { setName } = props;
return (
<button onClick={() => setName('fred')}>
);
};
Working Example:
function MyFunctionalComponent(props) {
const { setName } = props;
return <button onClick={() => setName("fred")}>Click me</button>;
}
class MyClassComponent extends React.Component {
constructor(props) {
super(props);
this.setName = this.setName.bind(this);
this.state = {
name: ""
};
}
setName(name) {
this.setState({
name: name
});
}
render() {
return (
<div>
<MyFunctionalComponent setName={this.setName} />
<br />
{this.state.name}
</div>
);
}
}
function App() {
return <MyClassComponent />;
}
ReactDOM.render(<App />, document.getElementById('root'))
<script crossorigin src="https://unpkg.com/react#16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.production.min.js"></script>
<div id="root"></div>
i'm new in reactjs. i was reading a documentation how to get an input value. But i'm still getting an undefine error. This is what i did.
class Test extends React.Component{
constructor(props){
super(props)
this.inputRef = React.createRef()
}
clickHandler(){
console.log(this.inputRef)
}
render(){
return(
<div>
<input type="text" ref={this.inputRef}/>
<button onClick={this.clickHandler}>click Me</button>
</div>
)
}
}
ReactDOM.render(<Test />, document.getElementById('root'));
Your issue was that you didn't bind the clickHandler to your component.
The easiest way is to use an arrow function instead of a class method:
clickHandler=()=>{
console.log(this.inputRef)
}
Otherwise in your constructor, you need to bind the clickHandler manually:
constructor(props){
super(props)
this.inputRef = React.createRef()
this.clickHandler = this.clickHandler.bind(this);
}
Here's an example of using an arrow function (which binds automatically)
class Test extends React.Component{
inputRef = React.createRef()
clickHandler=()=>{
console.log(this.inputRef.current.value)
}
render(){
return(
<div>
<input type="text" ref={this.inputRef}/>
<button onClick={this.clickHandler}>click Me</button>
</div>
)
}
}
ReactDOM.render(<Test />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"/>
I am trying to render a paragraph as soon as the you click the button.
Here is my code.
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.createText = this.createText.bind(this);
}
createText() {
return(
<p>hello friend</p>
)
}
render() {
return (
<div className="App">
<button onClick={this.createText}>Click</button>
</div>
);
}
}
export default App;
Here I am trying to render "hello friend" when the button is clicked. But is not working.
This is not the correct way because createText is a event handler it will not render the element, what you need is "Conditional rendering of elements".
Check Docs for more details Conditional Rendering.
Steps:
1- Use a state variable with initial value false.
2- Onclick of button update the value to true.
3- Use that state value for conditional rendering.
Working Code:
class App extends React.Component {
constructor() {
super();
this.state = {
isShow: false
}
this.createText = this.createText.bind(this);
}
createText() {
this.setState({ isShow: true })
}
render() {
return (
<div className="App">
<button onClick={this.createText}>Click</button>
{this.state.isShow && <p>Hello World!!!</p>}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app' />
I am trying to render a paragraph as soon as the you click the button.
Here is my code.
import React, { Component } from 'react';
class App extends Component {
constructor() {
super();
this.createText = this.createText.bind(this);
}
createText() {
return(
<p>hello friend</p>
)
}
render() {
return (
<div className="App">
<button onClick={this.createText}>Click</button>
</div>
);
}
}
export default App;
Here I am trying to render "hello friend" when the button is clicked. But is not working.
This is not the correct way because createText is a event handler it will not render the element, what you need is "Conditional rendering of elements".
Check Docs for more details Conditional Rendering.
Steps:
1- Use a state variable with initial value false.
2- Onclick of button update the value to true.
3- Use that state value for conditional rendering.
Working Code:
class App extends React.Component {
constructor() {
super();
this.state = {
isShow: false
}
this.createText = this.createText.bind(this);
}
createText() {
this.setState({ isShow: true })
}
render() {
return (
<div className="App">
<button onClick={this.createText}>Click</button>
{this.state.isShow && <p>Hello World!!!</p>}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app' />