Stack Overflow en español Asked on November 1, 2020
estoy haciendo una pequeña funcionalidad en react que desde un componente se dispara una funcion addProduct(item, type) el argumento item representa el objeto (ejemplo):
{product_name: 'can', product_price: 1200}
Y ese es el que pasa como item a la funcion arriba nombrada, luego esta funcion (dependiendo del type) agrega al state el item(objeto de arriba) a un array llamado:
canArray: []
Lo que me paso luego es el problema, cuando quiero borrar el ultimo de la lista tuve que añadirle un id al objeto dentro de la funcion addProduct que se iba incrementando al click pero si bien, agrega el objeto con el nuevo atributo id a medida que se agrega reemplaza en todos los atributos id de los objetos de el array (arriba mencionado) el nuevo valor.
Cabe señalar que el id lo iba creando en referencia al length del array canArray, intente hacer una validacion para que no tuviese ese comportamiento pero sin exito por lo que me es imposible hacer un filter ya que me repite los mismos id(del ultimo que se le agrego al objeto).
Adjunto el context que contiene la funcion:
class AppProvider extends React.Component {
constructor(props) {
super(props);
this.state = {
loginCredentials: {},
signUpCredentials: {},
isLoadingAuth: false,
isUserAuthenticated: false,
canArray: [],
quantity: null,
actions: {
loginInputData: this.loginInputData,
signIn: this.signIn,
signUpInputData: this.signUpInputData,
signUp: this.signUp,
addProduct: this.addProduct,
removeProduct: this.removeProduct
}
}
}
loginInputData = (text, name) => {
const { loginCredentials } = this.state;
const loginData = { [name]: text }
const newData = {...loginCredentials, ...loginData};
this.setState({
loginCredentials: newData
});
}
signIn = async(e) => {
const { loginCredentials } = this.state;
this.setState({
isLoadingAuth: true
});
const { signInUser } = this.props;
try {
const resp = await signInUser({variables: {
email: loginCredentials.email,
password: loginCredentials.password
}});
this.setState({
isUserAuthenticated: true,
isLoadingAuth: false
});
this.storeData(resp.data.signInUser.token);
} catch(err) {
console.log(err);
}
}
signUpInputData = (text, name) => {
const { signUpCredentials } = this.state;
const signUpData = { [name]: text }
const newData = {...signUpCredentials, ...signUpData}
this.setState({
signUpCredentials: newData
});
}
signUp = async() => {
const { signUpCredentials, isUserAuthenticated } = this.state;
this.setState({
isLoadingAuth: true
});
const { createUser } = this.props;
try {
const resp = await createUser({variables: {
name: signUpCredentials.name,
email: signUpCredentials.email,
password: signUpCredentials.password
}});
this.setState({
isUserAuthenticated: true,
isLoadingAuth: false
});
await AsyncStorage.setItem('isUserAuth', toString(isUserAuthenticated));
} catch(err) {
console.log('err ', err);
}
}
addProduct = (item, type) => {
const { canArray } = this.state;
if(type === 'canType') {
item.id = canArray.length
this.setState({
canArray: canArray.concat(item)
})
} else {
return true;
}
}
A continuacion el componente que consume las funciones de context:
const CAN_BOTTLE = { product_name: 'can', product_price: 1800 }
class CanProduct extends React.Component {
itemQuantity = () => {
return(
<Context.Consumer>
{co => {
console.log(co.canArray)
return(
<View>
<Text style={styles.number}>{co.canArray.length > 0 ? co.canArray.length : 0}</Text>
</View>
)
}}
</Context.Consumer>
)
}
render() {
return(
<Context.Consumer>
{co => {
return(
<View style={styles.productContainer}>
<View style={styles.productSelectionContainer}>
<Image source={can} style={styles.productImage} />
{this.itemQuantity()}
<View style={styles.productTextContainer}>
<Text style={styles.productTitle}>Can Bottles</Text>
<Text style={styles.productDesc}>Make sure the bottles are empty</Text>
</View>
<View style={styles.buttonAddContainer}>
<TouchableOpacity onPress={e => co.actions.addProduct(CAN_BOTTLE, "canType")}>
<Image source={addMore} />
</TouchableOpacity>
<TouchableOpacity onPress={e => co.actions.removeProduct("canType")}>
<Image source={less} style={styles.lessButton}/>
</TouchableOpacity>
</View>
</View>
</View>
)
}}
</Context.Consumer>
);
}
}
splice
es un método que altera (muta) el array original. Estás removiendo un item del array, y luego estás invocando setState
, pero el arreglo ya fue modificado. Esto produce inconsistencias entre el "estado" y la interfaz de usuario.
Se recomienda evitar este tipo de métodos porque producen estos efectos inesperados en la aplicación. Utiliza siempre setState
para mantener el "estado" de la aplicación en sincronía con la interfaz de usuario.
Si necesitas remover un elemento de un arreglo, puedes usar filter
ya que no modifica el arreglo original.
Para agregar algo al array, puedes usar Sintáxis Spread para "abrir" el arreglo existente, y luego agregar el nuevo elemento.
Ejemplo completo:
class App extends React.Component {
state = {
products: [
{ id: 1, product_name: "soda", product_price: 1800 },
{ id: 2, product_name: "rice", product_price: 400 },
{ id: 3, product_name: "can", product_price: 2000 }
]
};
inputName = React.createRef();
inputPrice = React.createRef();
handleRemove = (id) => {
this.setState((prevState) => {
return {
products: prevState.products.filter((p, i) => p.id !== id)
};
});
};
handleAdd = (name = "apples", price = 300) => {
this.setState((prevState) => {
const lastItem = prevState.products[prevState.products.length - 1];
return {
products: [
...prevState.products,
{ id: lastItem.id + 1, product_name: name, product_price: price }
]
};
});
};
render() {
const { products } = this.state;
return (
<div>
<ul>
{products.map((p, i) => (
<li key={p.id}>
id: {p.id} / {p.product_name} / {p.product_price}
<button onClick={() => this.handleRemove(p.id)}>Remover</button>
</li>
))}
</ul>
<label>
Nombre:
<input ref={this.inputName} type="text" />
</label>
<br />
<label>
Precio
<input ref={this.inputPrice} type="number" />
</label>
<br />
<button
onClick={() =>
this.handleAdd(
this.inputName.current.value,
this.inputPrice.current.value
)
}
>
Agregar
</button>
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Correct answer by Juan Marco on November 1, 2020
0 Asked on December 2, 2020 by johnatan-de-leon
0 Asked on December 1, 2020 by juan-rondon
1 Asked on December 1, 2020 by brayan-gonzalez
1 Asked on December 1, 2020 by gabriel-lenzina
1 Asked on December 1, 2020 by rral
1 Asked on November 30, 2020
1 Asked on November 30, 2020 by mariana
4 Asked on November 30, 2020 by daro
0 Asked on November 29, 2020 by javier-maldonado
1 Asked on November 29, 2020 by g-4
1 Asked on November 29, 2020 by jose-herrada
3 Asked on November 29, 2020 by subte
0 Asked on November 29, 2020 by martn
1 Asked on November 28, 2020 by noty
0 Asked on November 27, 2020 by zacktagnan
2 Asked on November 27, 2020 by sergio
0 Asked on November 27, 2020 by galogarsa-channel
Get help from others!
Recent Answers
© 2022 AnswerBun.com. All rights reserved. Sites we Love: PCI Database, MenuIva, UKBizDB, Menu Kuliner, Sharing RPP