javascript reactjs

javascript - Reaccionar: cambie this.state onClick renderizado con array.map()



reactjs (4)

Soy nuevo en React y Javascript, lo siento si esto es demasiado básico.

Tengo un componente de menú que muestra una animación en onClick y luego redirige la aplicación a otra ruta, /coffee .

Me gustaría pasar el valor en el que se hizo clic (seleccionado) para funcionar this.gotoCoffee y actualizar this.state.select , pero no sé cómo, ya que estoy asignando todos los elementos en this.state.coffees en el mismo onClick evento.

¿Cómo hago esto y actualizo this.state.select al valor seleccionado?

Mi código:

class Menus extends Component{ constructor (props) { super(props); this.state = { coffees:[], select: '''', isLoading: false, redirect: false }; }; gotoCoffee = () => { this.setState({isLoading:true}) setTimeout(()=>{ this.setState({isLoading:false,redirect:true}) },5000) } renderCoffee = () => { if (this.state.redirect) { return (<Redirect to={`/coffee/${this.state.select}`} />) } } render(){ const data = this.state.coffees; return ( <div> <h1 className="title is-1"><font color="#C86428">Menu</font></h1> <hr/><br/> {data.map(c => <span key={c}> <div> {this.state.isLoading && <Brewing />} {this.renderCoffee()} <div onClick={() => this.gotoCoffee()} <strong><font color="#C86428">{c}</font></strong></div> </div> </span>) } </div> ); } } export default withRouter(Menus);

He intentado pasar el valor así:

gotoCoffee = (e) => { this.setState({isLoading:true,select:e}) setTimeout(()=>{ this.setState({isLoading:false,redirect:true}) },5000) console.log(this.state.select) }

un me gusta así:

<div onClick={(c) => this.gotoCoffee(c)}

más o menos:

<div onClick={(event => this.gotoCoffee(event.target.value}

pero console.log(this.state.select) me muestra '' undefined '' para ambos intentos.

Parece que estoy pasando la Class con ''c''.

el navegador me muestra precisamente eso en la uri en la redirección:

http://localhost/coffee/[object%20Object]

Ahora, si paso ''c'' mapeado a {this.renderCoffee(c)} , que no es un evento onClick , me las arreglo para pasar los elementos de la matriz.

pero necesito pasar no el objeto, sino el valor ''c'' seleccionado a this.gotoCoffee(c) , y LUEGO actualizar this.state.select .

¿Cómo puedo solucionar esto?


De hecho, casi lo tienes en tu pregunta. Apuesto a que la razón por la cual su estado no está definido se debe a la naturaleza efímera del event . setState es una acción asincrónica y no siempre ocurre inmediatamente. Al pasar el evento directamente y permitir que la función proceda normalmente, el evento se libera antes de que se pueda establecer el estado. Mi consejo sería actualizar su función gotoCoffee para esto:

gotoCoffee = (e) => { const selectedCoffee = e.target.value this.setState({isLoading:true,select:selectedCoffee},() => {console.log(this.state.select}) setTimeout(()=>{ this.setState({isLoading:false,redirect:true}) },5000) }

Tenga en cuenta que moví su línea console.log a una función de devolución de llamada dentro de setState para que no se active hasta que el estado DESPUÉS se haya actualizado. Cada vez que use un componente de clase y necesite hacer algo inmediatamente después de actualizar el estado, use la función de devolución de llamada.


Puede pasar el index del elemento a gotoCoffee con cierre en render . Luego, en gotoCoffee , solo acceda a ese elemento como this.state.coffees[index] .

gotoCoffee = (index) => { this.setState({isLoading:true, select: this.state.coffees[index]}) setTimeout(()=>{ this.setState({isLoading:false,redirect:true}) },5000) } render(){ const data = this.state.coffees; return ( <div> <h1 className="title is-1"><font color="#C86428">Menu</font></h1> <hr/><br/> {data.map((c, index) => <span key={c}> <div> {this.state.isLoading && <Brewing />} {this.renderCoffee()} <div onClick={() => this.gotoCoffee(index)} <strong><font color="#C86428">{c}</font></strong></div> </div> </span>) } </div> ); } }


Todas las respuestas se ven bien y funcionan para usted y es obvio que cometió un error al no pasar el valor correcto en el controlador de clics. Pero como eres nuevo en esta era, pensé que era mejor cambiar tu implementación de esta manera:

  • No es necesario usar el constructor en absoluto y puede declarar una propiedad de estado con valores iniciales:

    class Menus extends Component{ state: { /* state properties */ }; }

  • Cuando declara funciones en el método de representación, siempre crea una nueva cada representación que tiene algún costo y no está optimizada. Es mejor si usas curry:

    handleClick = selected => () => { /* handle click */ } render () { // ... coffees.map( coffee => // ... <div onClick={ this.handleClick(coffee) }> // ... }

  • Puede redirigir con history.replace ya que envolvió su componente con withRouter y eso es útil aquí porque redirige al hacer clic y deshacerse del método renderCoffee :

    handleClick = selected => () => this.setState( { isLoading: true}, () => setTimeout( () => { const { history } = this.props; this.setState({ isLoading: false }); history.replace(`/${coffee}`); } , 5000) );

Dado que Redirect reemplaza la ruta y creo que desea que el cambio normal de página no reemplace, sugiero usar history.push lugar.


basado en su código, podría hacerlo de dos maneras.

onClick=(event) => this.gotoCoffee(event.target.value)

Este se parece al enfoque que desea.

onClick=() => this.gotoCoffee(c)

c estaría relacionado con su artículo en la matriz.