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

problemas al mandar un arreglo del frontend al backen utilizando Jquery.Ajax

0  Asked on December 2, 2020 by johnatan-de-leon

     

¿como guardar en local storage de select?

1  Asked on December 1, 2020 by gabriel-lenzina

   

Creacion y division de datasets

1  Asked on November 30, 2020 by brigido

     

HTML – Imagen rota en navegador chrome

0  Asked on November 29, 2020 by javier-maldonado

     

RegEx con misma vocal al inico y al final de string

1  Asked on November 29, 2020 by g-4

   

Necesito subir una API Rest a un servidor web

3  Asked on November 29, 2020 by subte

     

Enviar email desde python

0  Asked on November 29, 2020 by martn

     

CENTRAR SPAN DENTRO DE SECTION

1  Asked on November 28, 2020 by minor

   

Cambiar idioma de frontend a español en Magento 2

1  Asked on November 28, 2020 by noty

     

Problemas con checkbox

1  Asked on November 27, 2020 by e-diaz

   

Ask a Question

Get help from others!

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