I have a variable number that created an array, ex:
const numberVariable = 3;
const arr = Array(numberVariable).fill(0) // [0,0,0] //
And I have an Input component controlled by one state:
const [ input, setInput] = useState();
<InputUser value={input} onChange={(e) => {setInput(e.target.value) />
The problem:
When I make a map of the array, to create one Input for each element of the array, they change themselves, ex:
3 inputs, I write in the second and the other 2 get the same value;
How do I make them independent? knowing that creating 3 states manually is not an option, (I used 3 as an example, this is a variable number, changed every time)
code that create inputs based on array:
arr .map((number) => {
return (
<div key={number}>
<InputUser/>
</div>
);
});
CodePudding user response:
Just simplifying the correct answer a bit. The strategy is to store all the controlled input state as a list, and give each input an update function that only updates its position in the array.
const ManyInputs = ({howMany}) => {
// Like ["", "", ""]
const [inputs, setInputs] = useState(Array.from(new Array(howMany)).map(_ => ""));
const handleUserInputChange = position => (e) => {
// Update the correct input state
setInputs(...inputs.slice(0, position), e.target.value, ...inputs.slice(position 1));
};
return <>
{inputs.map((text, i) => <input
value={text}
onChange={handleUserInputChange(i)}>
</input>}
</>;
};
CodePudding user response:
So, you are trying to render X amount of input fields, and be able to manage all of them right ?
I'm not great at react too but i managed to do that, by getting help from here: https://zacjones.io/handle-multiple-inputs-in-react-with-hooks
const numberVariable = 3;
let arr = [];
for (let i = 0; i < numberVariable; i ) {
arr.push(i);
}
let initialState = {};
arr.forEach((element) => {
initialState[element] = "";
});
console.log(initialState);
const [input, setInput] = useState(initialState);
let inputName = 0;
const handleUserInputChange = (e) => {
const name = e.target.name;
const newValue = e.target.value;
setInput({ [name]: newValue });
};
const a = arr.map((number) => {
inputName ;
return (
<div key={number}>
<input
value={input[inputName]}
name={inputName}
onChange={handleUserInputChange}
></input>
</div>
);
});
One problem: there's "A component is changing a controlled input to be uncontrolled." alert on console, harmless but is there. I couldn't debug that. But this code replicates the behaviour you want and hopefully gives the general idea. You use name attribute to give them a unique name, and access it with e.target.name, then as the initial state, you have X amount of objects called 0: "", 1: "", created by the arr.forEach loop, so that you can change the according input field, onChange, by using setInput({ [name]: newValue });
.
https://codesandbox.io/s/beautiful-brattain-5foeu?file=/src/App.js
Hope that was decent, never answered a question before. The article i gave on top explains it further, you could possibly use a reducer like done there too, i used one state.
Step by step: User enters a numberVariable, which will be number of inputs created, let's say they entered 6
We make an array and push 0,1,2,3,4,5 in it.
Then we have the initialState object, for each element in the array, we create an object inside it, and initialState now looks like that; 0: "", 1: "", 2: "", ... and so on.
We pass initialState object as, well, initial state of our state.
When we are creating the input fields, we give them a unique name that will be same as objects inside initialState. So first input's name is 0, second input's name is 1 and so on...
Also every input is created with value={input[inputName]} so it gets the right object from the state.
All input's states are handled by handleUserInputChange.
Now our user started writing on one of the inputs, let's say he's writing on the input that is named 2. We get the name of that input with e.target.name, then we set our new state with setInput({ [e.target.name]: e.target.value }) So the object called 2, get's the input named 2's value. That's it. This happens for each input, and their values never get mixed.