Reputation: 21393
I am working on a task to practice react programming, this is the task - Change Username
Here is the explanation:
This application should allow the user to update their username by inputting a custom value and clicking the button.
The Username component is finished and should not be changed, but the App component is missing parts. Finish the App component so that the Username component displays the inputted text when the button is clicked.
The App component should use the React.useRef Hook to pass the input to the Username component for the input element and for the Username component.
For example, if the user inputs a new username of "John Doe" and clicks the button, the div element with id root should look like this:
<div><button>Change Username</button><input type="text"><h1>John Doe</h1></div>
This is the code given:
class Username extends React.Component {
state = { value: "" };
changeValue(value) {
this.setState({ value });
}
render() {
const { value } = this.state;
return <h1>{value}</h1>;
}
}
function App() {
function clickHandler() {}
return (
<div>
<button onClick={clickHandler}>Change Username</button>
<input type="text" />
<Username />
</div>
);
}
document.body.innerHTML = "<div id='root'></div>";
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
I tried a lot to understand how to solve this, but I am not able to fix this, how to solve this problem?
Upvotes: 1
Views: 5218
Reputation: 1080
In the real world you would probably do something like this: -
import React, { useRef } from "react";
import ReactDOM from "react-dom";
class Username extends React.Component {
state = { value: "" };
changeValue(value) {
this.setState({ value });
}
render() {
const { value } = this.state;
return <h1>{value}</h1>;
}
}
function App() {
const myRef = useRef();
function clickHandler() {
document.querySelector("h1").innerHTML = myRef.current.value;
}
return (
<div>
<button onClick={clickHandler}>Change Username</button>
<input type="text" ref={myRef} />
<Username />
</div>
);
}
document.body.innerHTML = "<div id='root'></div>";
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
document.querySelector("input").value = "John Doe";
document.querySelector("button").click();
setTimeout(() => console.log(document.getElementById("root").innerHTML));
Upvotes: 0
Reputation: 1514
This works
import React from 'react'
import ReactDOM from 'react-dom'
class Username extends React.Component {
constructor(props){
super(props);
this.state = {value: ""};
}
changeValue(value) {
this.setState({value: value});
}
render() {
const value = this.state.value;
return <h1>{value}</h1>;
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.userNameRef = React.createRef();
}
clickHandler() {
var name = document.getElementById('name_input').value;
this.userNameRef.current.setState({value: name});
}
render() {
return (
<div>
<button onClick={this.clickHandler.bind(this)}>Change Username</button>
<input id="name_input" type="text" />
<Username ref={this.userNameRef} />
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
Make sure you understand the code and don't be like me, forgetting the bind
method :-)
Upvotes: 0
Reputation: 786
This component structure probably isn't your best bet. Typically you want to have a Class component at the top with functional components on the bottom, and call those functional components within the Class component.
So rendering <button>
within App
is just making things hard for you. In App
you should just be rendering <Username />
and have <Username />
holding your logic:
class Username extends Component {
constructor(props){
this.state = { usernameValue: ''};
this.onInputChange = this.onInputChange.bind(this);
this.changeUsername = this.changeUsername.bind(this);
}
onInputChange(event) {
this.setState({usernameValue: event.target.value});
}
changeUsername() {
//Update username in the DB
db.record = this.state.usernameValue
}
render(){
return (
<div>//Wrapper div
<input onChange={this.onInputChange} value={this.state.usernameValue} />
<button onClick={this.changeUsername}>Change Username</button>
</div>
);
}
}
function App(){
return(
<Username />
);
}
I did this a different way than what you were trying as you were trying to update the username by clicking the button, which you can do, but it would be better to update the state as you input the username, then use the button click as a form submission or something along those lines.
A good resource for this is here
Upvotes: -1
Reputation: 2651
Just found it out. Seems like you need to use refs for everything. No state or anything allowed! Please note that you should not do it like that in a real world app :)
function App() {
const ref = React.useRef()
const inputRef = React.useRef()
function clickHandler() {
ref.current.changeValue(inputRef.current.value)
}
return (
<div>
<button onClick={clickHandler}>Change Username</button>
<input type="text" ref={inputRef} />
<Username ref={ref} />
</div>
);
}
Upvotes: 6