Reputation: 493
I have a number, n, that can be any value and I want to render n input fields while keeping track of each input's state but I'm having trouble figuring out how. For example, if n = 3, I want to render something like this:
<div>
<input onChange={(e) => setValue1(e.target.value)}/>
<input onChange={(e) => setValue2(e.target.value)}/>
<input onChange={(e) => setValue3(e.target.value)}/>
< /div>
In this example, I would manually need to create three states: value1, value2, value3. My goal is to have it dynamic so if in the future I change n to 4 or any other number, I don't have to manually create more states and mess with the component. Is there a good way to accomplish this using hooks?
Upvotes: 1
Views: 976
Reputation: 111
you can use useState([]) with array as default value for example
import "./styles.css"; import React, { useState } from "react";
export default function App() {
const n = 3;
const [values, setValues] = useState(new Array(n).fill(1, 0, n));
const handleChange = (i, value) => {
const v = [...values];
v[i] = value;
setValues(v);
};
const inputsRendrer = (values) => {
return values.map((v, i) => {
return (
<input
key={i}
value={values[i]}
onChange={(event) => handleChange(i, event.target.value)}
/>
);
});
};
return <div className="App">{inputsRendrer(values)}</div>;
}
new Array(n).fill(1, 0, n) // this create new array with values of 1 and length of n`
Upvotes: 0
Reputation: 143
This could be done with an array in the state, with the values in the inputs. Initialize with empty strings
const [values, setValues] = useState(Array(n).fill(""))
const handleChange = (e, i) => {
const copy = values;
copy[i] = e.target.value
setValues(copy)
}
return (
<div>
{Array(n).map((x,i) => (
<input value={values[i]} onChange={e => handleChange(e,i)} />
))}
</div>
)
Upvotes: 0
Reputation: 506
Maybe I would create a custom hook to generate my inputs like
import React, { useState } from "react";
const CreateInput = (n) => {
const array = new Array(n).fill("");
const [valueInput, setValueInput] = useState({});
const handleChange = (event) => {
const { name, value } = event.target;
setValueInput({
...valueInput,
[name]: value,
});
};
const Input = array.map((_, i) => (
<input key={i} name={i} onChange={handleChange} />
));
return {
Input,
};
};
const Inputs = () => {
const { Input } = CreateInput(3);
console.log(Input);
return <div>{Input}</div>;
};
export default Inputs;
Upvotes: 0
Reputation: 2604
You have to create a inputs state in order to track every input:
import React, { useState } from 'react';
import './style.css';
export default function App() {
const [inputs, setInputs] = useState(Array(10).fill(''));
const inputChangedHandler = (e, index) => {
const inputsUpdated = inputs.map((input, i) => {
if (i === index) {
return e.target.value;
} else {
return input;
}
});
setInputs(inputsUpdated);
};
return (
<div>
{inputs.map((input, i) => (
<input onChange={e => inputChangedHandler(e, i)} value={input} />
))}
</div>
);
}
You can check here, how things work: https://stackblitz.com/edit/react-sdzoqh
Upvotes: 1
Reputation: 25398
You can create a new array with useState
hook of size num
that is passed from its parent and then using its index i.e. i
you can change its input value using setValue
function.
Just for DEMO purpose and make the input
come to a new line so I've wrapped it into div
.
export default function App({ num }) {
const [arr, setValue] = useState(Array(num).fill(""));
console.log(arr);
function onInputChange(index, event) {
console.log(event.target.value);
setValue((os) => {
const temp = [...os];
temp[index] = event.target.value;
return temp;
});
}
return (
<div className="App">
{arr.map((n, i) => {
return (
<div key={i}>
<input onChange={(e) => onInputChange(i, e)} value={n} />
</div>
);
})}
</div>
);
}
Upvotes: 0