I am currently trying to learn React by making a Todo list (original I know). There a lot of concepts I haven't learnt yet (I'm still using class components) but I was wondering is there a recommended way to focus the input that appears when the edit button is pushed?
I tried using createRef but it still seems not to work. I'm wondering I the input should be a separate component that focuses onMount?
Any direction would be appreciated:
export class Item extends Component {
constructor(props){
super(props)
this.editInput = React.createRef()
this.state = {
editView: false
}
this.handleRemove = this.handleRemove.bind(this);
this.toggleView = this.toggleView.bind(this);
this.editMode = this.editMode.bind(this);
}
handleRemove(e){
this.props.remove(this.props.detail);
}
toggleView(){
this.setState(prevState => (
{editView: !prevState.editView }
))
}
editMode(){
this.toggleView();
this.editInput.current.focus();
}
render() {
const itemView = !this.state.editView ?<div className="item">{this.props.detail}</div> : <input ref={this.editInput} className="edit-item-input" placeholder={this.props.detail + "..."}></input> ;
return (
<div className="item-container">
{itemView}
<div className="buttons">
<button onClick={this.editMode} className="button button-edit">Edit</button>
<button onClick={this.handleRemove} className="button button-delete">Delete</button>
</div>
</div>
)
}
}
You could add the React autoFocus property, on the input element, and it should work as you want.
Related
I want to Know how to get the input text values in ReactJS using simple onclick event.I Know that it can be possible to do it like below code:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
Value: ""
};
}
render() {
const { library } = this.state;
return (
<div>
<input type="text" onChange={this.handleChange} />
<button type="button" onClick={this.handleSearch}>
save
</button>
</div>
);
}
handleChange = evt => {
this.setState({ Value: e.target.value });
};
handleSearch = evt => {
console.log(this.state.Value);
};
}
ReactDOM.render(<App />, document.getElementById("ResultContainer"));
I want to know is there any other way to get the input text without using onChange={ this.handleChange } ?
Like others have suggested, you could use a ref if you're feeling adventurous, but your code works as is.
However, just for learning purposes, you can use a ref to access the traditional DOM aspects of the mark-up that you would find using Vanilla JavaScript and HTML.
Simply create a ref variable and pass it to the input's ref attribute. See working sandbox: https://codesandbox.io/s/floral-lake-z9szd
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
Value: ""
};
}
inputText = React.createRef();
handleSearch = () => {
if (this.inputText.current) {
console.log(this.inputText.current.value);
}
};
render() {
return (
<div>
<input type="text" ref={this.inputText} />
<button type="button" onClick={this.handleSearch}>
save
</button>
</div>
);
}
}
Same concept but simpler with Functional Component and react hooks:
const App =()=>{
const [value,setValue]=React.useState();
const handleSearch = ()=>{
console.log(value)
}
return(
<div>
<input type="text" value={value} onChange={e=>setValue(e.target.value)} />
<button type="button" onClick={handleSearch}>
save
</button>
</div>
)
}
Dont know about reasoning why you want to to it different way. But sure there are tons of possibilities. First of all => when you are working on react application. Never forget that react is jsut layer above the DOM (when working on web app). So when you want to do some crazy stuff let react expose dom to you. In case of event handler you can get real dome node through event.target, which is button element. So you can do something like event.target.parentNode.childNodes[0].value or event.target.previousSibling.value. Imagination can be infinite you know :). Using ref is also another possible solution. But always think about: One time, someone will try to read this code. So do it easier for him.
I am trying to implement a collapsible component. I have designed it such as, on click of a button, a block of dynamic text will appear. I made a functional component and using the tags in a class. The name of the component is, CustomAccordion.jsx and using this component in Container.jsx
I have tried to create a button and a function for onClick event.
Part of the CustonAccordion.jsx
const handleToggle = () : string =>{
let content = this.nextElementSibling;
if (content.style.maxHeight){
content.style.maxHeight = null;
}else{
content.style.maxHeight = content.scrollHeight +'px';
}
}
export default function CustomAccordion(props: PropType): React.Component<*> {
const { title, children } = props
return(
<div>
<AccordionButton onClick={() => this.handleToggle()}>{title}</AccordionButton>
<AccordionContent>
<p>{children}
</p>
</AccordionContent>
</div>
)
}
Part of calling Container.jsx
<CustomAccordion title = {this.props.name}>
<p>This is the text passed to component.</p>
</CustomAccordion>
<br />
This does not show the expanded text and it seems that the click event does not work properly. I am very new in react, guessing the syntax might be incorrect.
In react you should generally try to avoid touching DOM directly unless you really have to.
Also you are accessing the handleToggle function wrongly. It should be onClick={() => handleToggle()} because this in your case is window/null and so it has no handleToggle method.
Instead you can use a stateful class component to achieve the same thing.
export default class CustomAccordion extends React.Component {
state = {show: false};
toggle = () => this.setState({show: !this.state.show});
render() {
const {title, children} = this.props;
const {show} = this.state;
return (
<div>
<AccordionButton onClick={this.toggle}>{title}</AccordionButton>
{show && (
<AccordionContent>
<p>{children}</p>
</AccordionContent>
)}
</div>
)
}
}
If you want to have some kind of animation, you can set different className based on the show state instead of adding/removing the elements.
So I have a component, called AddButton
export default class AddButton extends React.Component {
constructor(props) {
super(props);
}
addItem(e) {
this.btn.setAttribute('disabled', 'disabled');
this.props.addItem(e.target.getAttribute('data-row-index'))
}
render() {
return (
<div className="row">
<div className="col-md-12 text-center">
<button ref={btn => {this.btn = btn }} className="btn btn-success" onClick={this.addItem.bind(this)} data-row-index={this.props.rowIndex}>Add</button>
</div>
</div>
)
}
}
Some where else in the code I do:
if (this.props.addButton) {
rows.push(
<td key="add">
<AddButton
addItem={this.props.addItem}
rowIndex={this.props.rowIndex}
/>
</td>
)
}
So I have at one time 50 of these in a table at the end of the row. When one is clicked I wanted to disable all the buttons.
So as you can see I have done, in addItem(e):
addItem(e) {
this.btn.setAttribute('disabled', 'disabled');
this.props.addItem(e.target.getAttribute('data-row-index'))
}
But when I test this, only the button after the one is clicked is disabled. I want them all to be disabled
Any way I could modify this to achieve that?
React components have syntax like HTML DOM but they are not, they are modules and every time you use that module for example in your table it would be a new instance of that module. So if you want to share a state between them you have to pass it as props to them and you shouldn't treat them as HTML nodes.
I am trying to change the background color of a page to one of three colors, each with a respective button. The buttons onClick function is supposed to call a function to change the color, but for some reason it is not working and instead the last button is setting the background color of the page when first loaded. Why is this? The below code is not working.
class Game extends React.Component
{
setBgColor(bgColor)
{
document.body.style.backgroundColor = bgColor;
}
render()
{
return(
<div id = "buttonWrapper">
<button id = "redButton" onClick = {this.setBgColor("red")}>RED</button>
<button id = "greenButton" onClick = {this.setBgColor("green")}>GREEN</button>
<button id = "blueButton" onClick = {this.setBgColor("blue")}>BLUE</button>
</div>
);
}
Thank you in advance.
#Mickael-conner, please use the following code for defining functions for your onClick events:
class Game extends React.Component
{
setBgColor(bgColor)
{
document.body.style.backgroundColor = bgColor;
}
render()
{
return(
<div id="buttonWrapper">
<button id="redButton" onClick={() => this.setBgColor("red")}>RED</button>
<button id="greenButton" onClick={() => this.setBgColor("green")}>GREEN</button>
<button id="blueButton" onClick={() => this.setBgColor("blue")}>BLUE</button>
</div>
);
}
The following article has explained different ways for defining functions inside React components:
5 Approaches for Handling this
I'm sure this is something trivial but I can't seem to figure out how to access the value of my button when the user clicks the button. When the page loads my list of buttons renders correctly with the unique values. When I click one of the buttons the function fires, however, the value returns undefined. Can someone show me what I'm doing wrong here?
Path: TestPage.jsx
import MyList from '../../components/MyList';
export default class TestPage extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.handleButtonClick = this.handleButtonClick.bind(this);
}
handleButtonClick(event) {
event.preventDefault();
console.log("button click", event.target.value);
}
render() {
return (
<div>
{this.props.lists.map((list) => (
<div key={list._id}>
<MyList
listCollection={list}
handleButtonClick={this.handleButtonClick}
/>
</div>
))}
</div>
);
}
}
Path: MyListComponent
const MyList = (props) => (
<div>
<Button onClick={props.handleButtonClick} value={props.listCollection._id}>{props.listCollection.title}</Button>
</div>
);
event.target.value is for getting values of HTML elements (like the content of an input box), not getting a React component's props. If would be easier if you just passed that value straight in:
handleButtonClick(value) {
console.log(value);
}
<Button onClick={() => props.handleButtonClick(props.listCollection._id)}>
{props.listCollection.title}
</Button>
It seems that you are not using the default button but instead some sort of customized component from another libray named Button.. if its a customezied component it wont work the same as the internatls might contain a button to render but when you are referencing the event you are doing it throug the Button component