function sample () {
return (
<div>
<input/>
<input/>
<input/>
.
.
?
<button onClick={ ? ? ? ? }> ADD NEW INPUT <button>
</div>
)}
Let's pretend we're working on this code. Here, by clicking 'ADD NEW INPUT' button tag, I want to input tag to keep created.
I have looked for createElement() and appendChild(), but all I can do was only append just 1 HTML element to existing one.
I want to know how we can make a function or set up a logic to solve this kind of problem.
const [input, setInput] = useState([<input defaultValue={1} />]);
return (
<div>
{input.map((item) => (
<div>{item}</div>
))}
<button
className="block p-5 mx-4 rounded-lg bg-emerald-600"
onClick={() => {
setInput([...input, <input defaultValue={input.length + 1} />]);
}}
>
Append
</button>
</div>
);
You can check the below implementation
import React, { useState } from "react";
const Input = () => <input />; //input component
const Component = () => {
const [inputs, setInputs] = useState([]); //create a state to keep all generated inputs
return (
<div>
//re-render all inputs whenever we have a new input
{inputs.map((Input, index) => (
<Input key={index} />
))}
//set a new input into the input list
<button onClick={() => setInputs([...inputs, Input])}>Generate input</button>
</div>
);
};
export function App() {
return <Component />;
};
Here is the playground
This question already has answers here:
How to access a DOM element in React? What is the equilvalent of document.getElementById() in React
(9 answers)
Closed 2 years ago.
When i click the play button, it shows an error saying:
'Cannot read property 'play' of null '
Here is my code:
import React, {useState} from 'react';
import ReactDOM from 'react-dom';
const App = () => {
const player = document.getElementById('player')
const [musicIndex, setMusicIndex] = useState(0);
const musicArray = [
{
title: 'koe no katachi',
link: 'aiko- 恋をしたのはmusic video.mp3'
},
{
title: 'stay alive',
link: 'ReZero ED Ending 2 FullEmilia (Rie Takahashi) - Stay AliveENG Sub.mp3'
},
{
title: 'Tenshi ni fureta',
link: '[K-ON AMV] 天使にふれたよ.mp3'
}
]
return (
<div className="spotify-clone">
<audio id='player' className='player' src={`Songs/${musicArray[musicIndex].link}`} controls></audio>
<h3>{musicArray[musicIndex].link}</h3>
<div className='button'>
<button onClick={() => setMusicIndex(musicIndex + 1)}>Next</button>
<button onClick={() => setMusicIndex(musicIndex - 1)}>Prev</button>
<button onClick={() => player.play()}>Play</button>
<button onClick={() => player.pause()}>Pause</button>
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById('music-player'));
You need to use ref
import React, {useState,useRef} from 'react';
export const App = () => {
const playerRef = useRef<HTMLAudioElement>(null);
const [musicIndex, setMusicIndex] = useState(0);
const musicArray = [
{
title: 'koe no katachi',
link: 'aiko- 恋をしたのはmusic video.mp3'
},
{
title: 'stay alive',
link: 'ReZero ED Ending 2 FullEmilia (Rie Takahashi) - Stay AliveENG Sub.mp3'
},
{
title: 'Tenshi ni fureta',
link: '[K-ON AMV] 天使にふれたよ.mp3'
}
]
return (
<div className="spotify-clone">
<audio id='player' ref={playerRef}
className='player'
src={`Songs/${musicArray[musicIndex].link}`} controls>
</audio>
<h3>{musicArray[musicIndex].link}</h3>
<div className='button'>
<button onClick={() => setMusicIndex(musicIndex + 1)}>Next</button>
<button onClick={() => setMusicIndex(musicIndex - 1)}>Prev</button>
<button onClick={() => playerRef?.current?.play()}>Play</button>
<button onClick={() => playerRef?.current?.pause()}>Pause</button>
</div>
</div>
);
}
You could try maybe initializing the player inline:
<button onClick={() => document.getElementById('player').play()}>Play</button>
I don't know exactly if this helps
You shouldn't use document.getElementById here, as at this point of time the DOM is not yet created. So instead of doing this, you should declare a new variable with useState: const [player, setPlayerValue] = useState('');
and then in useEffect method set the value of player variable with document.getElementById('player').
Hello i have a question if some one could help.
I created a react app with tree buttons when i click on every button the code shows and hide text.
But i wanted when i click for example on button 2 the text from button 1 and 3 to be hidden. And the same for every button if i click on button 3 the text from button 1 and 2 to be hidden also.
import React, { useState } from 'react';
export default class Tinfo extends React.Component{
constructor(props){
super(props);
this.state = { show: new Array(3).fill(false) };
this.baseState = this.state
}
resetState = () => {
this.setState(this.baseState)
}
toggleDiv = (index) => {
var clone = Object.assign( {}, this.state.show );
switch(clone[index]){
case false:
clone[index] = true
break;
case true:
clone[index] = false
break;
}
this.setState({ show: clone });
}
render(){
return(
<div>
{ this.state.show[0] && <div id="tinfo"> First Div </div>}
{ this.state.show[1] && <div id="tinfo"> Second Div </div>}
{ this.state.show[2] && <div id="tinfo"> Third Div </div> }
<button onClick={() => this.toggleDiv(0)}>button 1</button>
<button onClick={() => this.toggleDiv(1)}>button 2</button>
<button onClick={() => this.toggleDiv(2)}>button 3</button>
</div>
)
}
}
since only one can be shown, then just reset the state
toggleDiv = index => {
const show = new Array(3).fill(false);
show[index] = true;
this.setState({
show
});
}
although this should now be named showDiv as it sets the state and hides the rest, it's not a toggle.
I am saving a value through a textfield and after the button click, I wanted to disable the button so the user can't press it again.
I am using React.js for the implementation of the app.
<button type="button" className="btn btn-info round btn-glow px-2 float-right">Confirm</button>
create a state like this
state = {
btnIsDisable: false
}
set in button
<button disabled={this.state.btnIsDisable} type="button" className="btn btn-info round btn-glow px-2 float-right">Confirm</button>
in onClick handler change the state
this.setState({btnIsDisable:true});
You have to create a class component and set the initial state button state to true and then change it to false when the click function is fired
// Initial state
this.state = {
buttonEnabled : true
};
// onClick function
onClick(event){
this.setState({buttonEnabled: false});
}
render() {
const { buttonEnabled } = this.state;
return (
<div>
<button onClick={this.onClick} disabled={buttonEnabled}>
Your content here
<button>
</div>
)
}
// declare some variable for holding your button's state
state = {
disabled: false
}
...
onConfirmButtonClick () => {
// set state.disabled as true
this.setState({ disabled: true })
}
render () {
return (
...
<button
disabled={this.state.disabled} // add disabled attribute to your button along with your state
type="button"
className="btn btn-info round btn-glow px-2 float-right"
>
Confirm
</button>
)
}
Working code in the link: https://codepen.io/stanlee94/pen/gNOLxb
class Button extends React.Component {
state = {
disabled: false,
pointerStyle: 'pointer'
}
handleClick = () => {
//Do your logic here
console.log('Record added');
this.setState({
disabled: true,
pointerStyle: 'no-drop'
});
}
render() {
return(
<button disabled={this.state.disabled} type="button" onClick={this.handleClick}
style={{ cursor: this.state.pointerStyle }}>Confirm</button>
);
}
}
It will add an invalid type of pointer after you click to provide a good user experience to your user.
I have file upload input:
<input onChange={this.getFile} id="fileUpload" type="file" className="upload"/>
And I handle upload this way:
getFile(e) {
e.preventDefault();
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = (theFile) => {
var data = {
blob: theFile.target.result, name: file.name,
visitorId: this.props.socketio.visitorId
};
console.log(this.props.socketio);
this.props.socketio.emit('file-upload', data);
};
reader.readAsDataURL(file);
}
If I upload same file twice, then upload event is not fired. How can I fix that? For simple js code it was enough to do the following: this.value = null; in change handler. How can I do it with ReactJS?
I think you can just clear the input value like this :
e.target.value = null;
File input cannot be controlled, there is no React specific way to do that.
Edit For old browsers (<IE11), you can use one of the following techniques.
See http://jsbin.com/zurudemuma/1/edit?js,output (tested on IE10 & 9)
What worked for me was setting a key attribute to the file input, then when I needed to reset it I update the key attribute value:
functionThatResetsTheFileInput() {
let randomString = Math.random().toString(36);
this.setState({
theInputKey: randomString
});
}
render() {
return(
<div>
<input type="file"
key={this.state.theInputKey || '' } />
<button onClick={this.functionThatResetsTheFileInput()} />
</div>
)
}
That forces React to render the input again from scratch.
This work for me - ref={ref => this.fileInput = ref}
<input id="file_input_file" type="file" onChange={(e) => this._handleFileChange(e)} ref={ref=> this.fileInput = ref} />
then in my case once the file was uploaded to the server , I clear it by using the statement below
this.fileInput.value = "";
I do it by updating key inside my file input.
This will force a re-render and previously selected file will go away.
<input type="file" key={this.state.inputKey} />
Changing the state inputKey will re-render the component.
One way to change the inputKey will be to always set it to Date.now() on click of a button which is supposed to clear the field.
With every click onClick you can reset the input, so that even with the same file onChange will be triggered.
<input onChange={this.onChange} onClick={e => (e.target.value = null)} type="file" />
import React, { useRef } from "react";
export default function App() {
const ref = useRef();
const reset = () => {
ref.current.value = "";
};
return (
<>
<input type="file" ref={ref} />
<button onClick={reset}>reset</button>
</>
);
}
The following worked for me using React Hooks. This is done using what is known as a "controlled input". That means, the inputs are controlled by state, or their source of truth is state.
TL;DR Resetting the file input was a two-step process using both the useState() and useRef() hooks.
NOTE: I also included how I reset a text input in case anyone else was curious.
function CreatePost({ user }) {
const [content, setContent] = React.useState("");
const [image, setImage] = React.useState(null); //See Supporting Documentation #1
const imageInputRef = React.useRef(); //See Supporting Documentation #2
function handleSubmit(event) {
event.preventDefault(); //Stop the pesky default reload function
setContent(""); //Resets the value of the first input - See #1
//////START of File Input Reset
imageInputRef.current.value = "";//Resets the file name of the file input - See #2
setImage(null); //Resets the value of the file input - See #1
//////END of File Input Reset
}
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Add Post Content"
onChange={event => setContent(event.target.value)}
value={content} //Make this input's value, controlled by state
/>
<input
type="file"
onChange={event => setImage(event.target.files[0])} //See Supporting Doc #3
ref={imageInputRef} //Apply the ref to the input, now it's controlled - See #2
/>
<button type="submit">Submit Form</button>
</form>
</div>
)
};
Supporting Documentation:
useState Hook
Returns a stateful value, and a function to update it.
useRef Hook
If you pass a ref object to React, React will set its current property to the corresponding DOM node whenever that node changes.
Using files from web apps
If the user selects just one file, it is then only necessary to consider the first file of the list.
You can also include this in your input element if you know you are not going to be using the built-in file input value at all.
<input value={""} ... />
This way the value is always reset to the empty string on render and you don't have to include it awkwardly in an onChange function.
I know file input is always uncontrolled however the following code still works in my own porject, I can reset the input with no problems at all.
constructor(props) {
super(props);
this.state = {
selectedFile: undefined,
selectedFileName: undefined,
imageSrc: undefined,
value: ''
};
this.handleChange = this.handleChange.bind(this);
this.removeImage = this.removeImage.bind(this);
}
handleChange(event) {
if (event.target.files[0]) {
this.setState({
selectedFile: event.target.files[0],
selectedFileName: event.target.files[0].name,
imageSrc: window.URL.createObjectURL(event.target.files[0]),
value: event.target.value,
});
}
}
// Call this function to reset input
removeImage() {
this.setState({
selectedFile: undefined,
selectedFileName: undefined,
imageSrc: undefined,
value: ''
})
}
render() {
return (
<input type="file" value={this.state.value} onChange={this.handleChange} />
);
}
We can reset file input by using key = {this.state.fileInputKey} and initialsing fileInputKey to Date.now() in constructor state.
On file upload success , we need to again assign fileInputKey: Date.now(), so it will have different value than previous and it create new file input component on next render()
We can also do this manually by clicking button to clear/reset file Input
Below is the working code :
import React from "react";
import { Button } from "reactstrap";
class FileUpload extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedFile: null,
fileInputKey: Date.now(),
message: ""
};
this.handleClear = this.handleClear.bind(this);
this.onClickHandler = this.onClickHandler.bind(this);
this.onChangeHandler = this.onChangeHandler.bind(this);
}
onChangeHandler = event => {
this.setState({
selectedFile: event.target.files
});
};
onClickHandler = () => {
if (this.state.selectedFile === null) {
this.setState({
message: "Please select File"
});
return;
}
//axios POST req code to send file to server
{
/**
const data = new FormData()
data = this.state.selectedFile[0]
axios.post("http://localhost:8080/api/uploadFile/", data)
.then(res => {
if (res.status == 200) {
// upload success
}
})
.catch(err => {
//message upload failed
})
*/
}
//after upload to server processed
this.setState({
selectedFile: null,
fileInputKey: Date.now(),
message: "File Uploaded"
});
};
handleClear() {
this.setState({
selectedFile: null,
fileInputKey: Date.now(),
message: ""
});
}
render() {
return (
<div>
<input
type="file"
key={this.state.fileInputKey}
class="form-control"
onChange={this.onChangeHandler}
/>
<button
type="button"
class="btn btn-success btn-block"
onClick={this.onClickHandler}
>
Upload
</button>
<Button
type="button"
value="Clear"
data-test="clear"
onClick={this.handleClear}
>
{" "}
Clear{" "}
</Button>
<br />
<label>{this.state.message}</label>
</div>
);
}
}
export default FileUpload;
Here is my solution using redux form
class FileInput extends React.Component {
constructor() {
super();
this.deleteImage = this.deleteImage.bind(this);
}
deleteImage() {
// Just setting input ref value to null did not work well with redux form
// At the same time just calling on change with nothing didn't do the trick
// just using onChange does the change in redux form but if you try selecting
// the same image again it doesn't show in the preview cause the onChange of the
// input is not called since for the input the value is not changing
// but for redux form would be.
this.fileInput.value = null;
this.props.input.onChange();
}
render() {
const { input: { onChange, value }, accept, disabled, error } = this.props;
const { edited } = this.state;
return (
<div className="file-input-expanded">
{/* ref and on change are key properties here */}
<input
className="hidden"
type="file"
onChange={e => onChange(e.target.files[0])}
multiple={false}
accept={accept}
capture
ref={(input) => { this.fileInput = input; }}
disabled={disabled}
/>
{!value ?
{/* Add button */}
<Button
className="btn-link action"
type="button"
text="Add Image"
onPress={() => this.fileInput.click()}
disabled={disabled}
/>
:
<div className="file-input-container">
<div className="flex-row">
{/* Image preview */}
<img src={window.URL.createObjectURL(value)} alt="outbound MMS" />
<div className="flex-col mg-l-20">
{/* This button does de replacing */}
<Button
type="button"
className="btn-link mg-b-10"
text="Change Image"
onPress={() => this.fileInput.click()}
disabled={disabled}
/>
{/* This button is the one that does de deleting */}
<Button
type="button"
className="btn-link delete"
text="Delete Image"
onPress={this.deleteImage}
disabled={disabled}
/>
</div>
</div>
{error &&
<div className="error-message"> {error}</div>
}
</div>
}
</div>
);
}
}
FileInput.propTypes = {
input: object.isRequired,
accept: string,
disabled: bool,
error: string
};
FileInput.defaultProps = {
accept: '*',
};
export default FileInput;
In my case I had a functional component and after selecting a file it suppose to set the file name in the state so using any solution above was failing except the ref one which i fixed like this.
const fileUpload = props => {
const inputEl = useRef(null)
const onUpload = useCallback(e => {
uploadFile(fileDetails)
.then(res => {
inputEl.current.value = ''
})
.catch(err => {
inputEl.current.value = ''
})
})
return (
<input type='file' ref={inputEl} onChange={handleChange} />
<Button onClick={onUpload}>Upload</Button>
)
}
I recently got stumbled into this issue to reset the File type input field. I think it is still a milestone for most developers. So I thought I should share my solution.
Since we are listening to the onChange event to update the image file into some of our states, we will have our component rerendered once we set the state. In such case, we can specify the value of the input file as empty like value='' which will cause the input field to reset its value after each change of its value.
<input
type="file"
value=''
onChange={onChangeFnc}
/>