AnswerBun.com

Problemas creando un id para objeto javascript

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>
        );
    }
    }

One Answer

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

Add your own answers!

Related Questions

Expresión regular para palabras en php

1  Asked on August 27, 2021 by carlos-valdes-web

   

mostrar solo los elementos true de un array

2  Asked on August 26, 2021 by fernando-cruz

   

como arreglar este stored procedure?

2  Asked on August 26, 2021 by luis

     

Ayuda con array tridimensional

1  Asked on August 26, 2021

   

Cards Bootstrap

1  Asked on August 26, 2021 by nat-najera

     

Inicialización: corchetes { }, asignación =, y otras formas

1  Asked on August 26, 2021 by federico-choy

 

Acceso a RowCommand aspx

1  Asked on August 26, 2021 by ledferoz10

       

¿Como recargar un div al enviar un formulario?

1  Asked on August 26, 2021 by jos-carlos-castillo

       

¿Donde inicializar una BD SQLite en Android?

2  Asked on August 26, 2021 by antonio-ruiz

     

Ask a Question

Get help from others!

© 2023 AnswerBun.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP