tutorial - recorrer array de objetos javascript
Cómo borrar valores de entrada de forma dinámica en reaccionar. (4)
Tengo una forma dinámica como componente funcional que se genera a través de un componente basado en clase. Quiero hacer un botón de reinicio que borre los valores del campo de entrada y establezca el estado en una matriz nula.
El código completo está disponible aquí: https://codesandbox.io/s/beautiful-archimedes-o1ygt
Quiero hacer un botón de reinicio, borrar todos los valores de entrada e inicializar la matriz de valores de elementos en nulo. Incluso si establezco los valores en nulo, no borra el campo de entrada.
Sin embargo, el problema al que me enfrento es que, dado que es un formulario dinámico y un componente funcional, no tiene un estado predefinido para cada campo de formulario individual, lo que dificulta establecer el valor en nulo. ¿Puede alguien ayudarme? Estoy atascado en esto desde hace mucho tiempo.
A ver si eso funciona para ti:
Ejemplo de trabajo en CodeSandbox
Debido a que ya estaba usando ganchos en parte de su código, he convertido su clase en un componente funcional usando ganchos (mi consejo: aprenda ganchos y olvídese de los componentes de la clase).
He agregado una propiedad de
value
a su
INITIAL_STATE
para que mantenga el valor de entrada para cada
inputItem
.
CÓDIGO completo:
index.js
import React, { useState } from "react";
import ReactDOM from "react-dom";
import FormV2 from "./FormV2";
import "./styles.css";
function App() {
const INITIAL_STATE = [
{
name: "item1",
description: "item1",
group: "groupA",
dtype: "str",
value: "" // ADDED VALUE PROPERTY TO KEEP THE INPUT VALUE
},
{
name: "item2",
description: "item2",
group: "groupA",
dtype: "str",
value: ""
},
{
name: "item3",
description: "item3",
group: "groupB",
dtype: "str",
value: ""
},
{
name: "item4",
description: "item4",
group: "groupB",
dtype: "str",
value: ""
}
];
const [inputItems, setInputItems] = useState(INITIAL_STATE);
function handleChange(event, index) {
const newValue = event.target.value;
setInputItems(prevState => {
const aux = Array.from(prevState);
aux[index].value = newValue;
return aux;
});
}
function handleReset() {
console.log("Reseting Form to INITIAL_STATE ...");
setInputItems(INITIAL_STATE);
}
function handleSubmit() {
inputItems.forEach(item =>
console.log(
"I will submit input: " + item.name + ", which value is: " + item.value
)
);
}
return (
<FormV2
handleSubmit={handleSubmit}
handleReset={handleReset}
handleChange={handleChange}
inputItems={inputItems}
/>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
FormV2.js
import React from "react";
function FormV2(props) {
const formInputItems = props.inputItems.map((item, index) => (
<div key={item.name}>
{item.name + ": "}
<input
type="text"
data-type={item.dtype}
data-group={item.group}
placeholder={item.description}
value={item.value}
onChange={event => props.handleChange(event, index)}
/>
</div>
));
return (
<React.Fragment>
<form>{formInputItems}</form>
<button onClick={props.handleSubmit}>Submit</button>
<button onClick={props.handleReset}>Reset</button>
<div>State: {JSON.stringify(props.inputItems)}</div>
</React.Fragment>
);
}
export default FormV2;
Aquí hay un codesandbox para mostrarle cómo restablecer los elementos: https://codesandbox.io/s/romantic-heisenberg-93qi7
También dejé una nota para usted sobre cómo hacer que esto funcione con sus datos de API, vea el comentario en
onChangeText()
El problema es que las entradas no están controladas por estado como lo ha deducido.
Debemos crear un objeto actualizado para cada elemento de su API, dándole un
value
prop.
index.js
import React from "react";
import ReactDOM from "react-dom";
import Cart from "./Cart";
import "./styles.css";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
Items: [],
itemvalues: [{}]
};
this.onChangeText = this.onChangeText.bind(this);
this.getItems = this.getItems.bind(this);
this.handleReset = this.handleReset.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.findFieldIndex = this.findFieldIndex.bind(this);
this.trimText = this.trimText.bind(this);
}
getItems = () => {
/*if the data is coming from an API, store it in an array then .map() over it.
we can add a value prop to the object like:
so you can do something like:
const newItems = [...apiData].map((item) => {
return {
...item,
value: ""
}
})
this.setState({
Items: newItems
})
*/
this.setState({
Items: [
{
name: "item1",
description: "item1",
group: "groupA",
dtype: "str",
value: ""
},
{
name: "item2",
description: "item2",
group: "groupA",
dtype: "str",
value: ""
},
{
name: "item3",
description: "item3",
group: "groupB",
dtype: "str",
value: ""
},
{
name: "item4",
description: "item4",
group: "groupB",
dtype: "str",
value: ""
}
]
});
};
onChangeText = e => {
const updatedItems = [...this.state.Items].map(item => {
if (item.name === e.target.name) {
return {
...item,
value: e.target.value
};
} else {
return item;
}
});
const updatedItemValues = [...updatedItems].reduce((obj, curr) => {
if (!obj[curr.group]) {
obj[curr.group] = [];
}
obj[curr.group] = [...obj[curr.group], { [curr.name]: curr.value }];
return obj;
}, {});
this.setState({
...this.state,
Items: updatedItems,
itemvalues: updatedItemValues
});
};
findFieldIndex = (array, name) => {
return array.findIndex(item => item[name] !== undefined);
};
trimText(str) {
return str.trim();
}
handleReset = () => {
const resetedItems = [...this.state.Items].map(item => {
return {
...item,
value: ""
};
});
this.setState(
{
...this.state,
Items: resetedItems,
itemvalues: []
},
() => console.log(this.state)
);
};
handleSubmit = () => {
console.log(this.state.itemvalues);
};
render() {
return (
<div>
{
<Cart
Items={this.state.Items}
getItems={this.getItems}
handleSubmit={this.handleSubmit}
handleReset={this.handleReset}
onChangeText={this.onChangeText}
/>
}
</div>
);
}
}
Cart.js
import React, { useEffect } from "react";
import Form from "./Form";
const Cart = props => {
useEffect(() => {
props.getItems(props.Items);
}, []);
return (
<div>
<Form Items={props.Items} onChangeText={props.onChangeText} />
<button onClick={props.handleSubmit}>Submit</button>
<button onClick={props.handleReset}>Reset</button>
</div>
);
};
export default Cart;
El componente Cart puede permanecer prácticamente igual, no es necesario que
props.items
para
useEffect()
dependencia
useEffect()
.
Form.js
import React from "react";
const Form = props => {
return (
<div>
{props.Items.map(item => {
return (
<input
name={item.name}
placeholder={item.description}
data-type={item.dtype}
data-group={item.group}
onChange={e => props.onChangeText(e)}
value={item.value}
/>
);
})}
</div>
);
};
export default Form;
Ahora, en el componente
Form
, proporcionamos a cada entrada una proposición de valor que está conectada al elemento en nuestro estado de componente principal más alto.
Eso es prácticamente todo lo que necesitas para restablecer los valores.
Desea administrar el estado del número desconocido de elementos
N
, una forma de lograrlo es mediante la administración de un solo objeto que contenga todos los estados, por ejemplo,
setValuesManager
administra
N
entradas y haciendo clic en el
button
restablecer su estado:
function TextAreaManager() {
const [valuesManager, setValuesManager] = useState([...items]);
return (
<Flexbox>
{valuesManager.map((value, i) => (
<TextBoxItem
key={i}
value={value}
onChange={e => {
valuesManager[i] = e.target.value;
setValuesManager([...valuesManager]);
}}
/>
))}
<PinkButton
onClick={() =>
setValuesManager([...Array(valuesManager.length).fill('''')])
}
>
Reset All
</PinkButton>
</Flexbox>
);
}
Manifestación:
Para controlar los valores de los componentes secundarios (Elementos) que supongo que son campos de entrada, debe pasar sus valores desde su componente principal.
Por lo tanto, cada uno de sus artículos tendrá un valor de
item.value
que se almacena en el estado del componente principal.
Eso significa que en el componente principal podrá definir un método que borra todos los valores de los elementos que está almacenando en su estado. Eso probablemente se verá algo así como
resetInputs = () => {
this.setState({
inputFields: this.state.inputFields.map(inputField => {
...inputField,
value: ''''
}
})
}
También deberá escribir qué tipo de etiqueta desea que funcione para su código, como entrada.
Entonces, lo que terminará con el código del componente secundario que compartió es algo como:
const Form = (props) => {
return (
<div>
{props.Items.map(item => (
<input
name={item.name}
value={item.value}
placeholder={item.description}
onChange={e => props.onChangeText(e)}
/>
)
)}
</div>
);
}
export default Form