react - 更改 this.state onClick 呈现的 array.map()

IT技术 javascript reactjs
2021-05-03 14:26:31

我是 React 和 JavaScript 的新手。

我有一个 Menu 组件,它呈现动画onClick,然后将应用程序重定向到另一条路线/coffee.

我想将单击(选择)的值传递给 functionthis.gotoCoffee和 update this.state.select,但我不知道如何,因为我this.state.coffees在同一onClick事件中映射所有项目

如何执行此操作并更新this.state.select为单击的值?

我的代码:

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

我试过像这样传递值:

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

像这样:

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

或者:

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

两次尝试都console.log(this.state.select)向我显示“ undefined”。

看来我正在通过Class'c'。

浏览器在重定向的 uri 上准确地向我显示了这一点:

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


现在,如果我将映射的 'c' 传递给{this.renderCoffee(c)},这不是onClick事件,我设法传递数组项。

但我需要传递的不是对象,而是点击的值 'c' 到this.gotoCoffee(c),然后更新this.state.select

我该如何解决?

4个回答

您可以将index元素传递gotoCoffeewith 闭包 in render然后在gotoCoffee,只需访问该元素作为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>
    );
  }
}

所以根据你的代码,你可以通过几种方式来做到这一点。

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

这看起来像你想要的方法。

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

c 将与您在数组中的项目有关。

所有的答案看起来都不错并且对你有用,很明显你没有在点击处理程序中传递正确的值而犯了一个错误。但是由于您是这个时代的新手,我认为最好以这种方式更改您的实现:

  • 根本不需要使用构造函数,您可以使用初始值声明状态属性:

    class Menus extends Component{
        state= {
            /* state properties */
        };
    }
    
  • 当您在 render 方法中声明函数时,它总是会在每次渲染时创建一个新的函数,该函数具有一定的成本且未优化。如果你使用柯里化会更好:

    handleClick = selected => () => { /* handle click */ }
    render () {
        // ...
        coffees.map( coffee =>
            // ...
             <div onClick={ this.handleClick(coffee) }>
            // ...
    }
    
  • 您可以使用 重定向,history.replace因为您用它包裹了组件​​,withRouter这在这里很有帮助,因为您可以在单击时重定向并摆脱renderCoffee方法:

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

由于Redirect替换了路由,我认为您希望正常的页面更改而不是替换,我建议history.push改用。

你实际上几乎已经在你的问题中了。我敢打赌,您的状态未定义的原因是event. setState是一个异步操作,并不总是立即发生。通过直接传递事件并允许函数正常进行,事件在状态被设置之前被释放。我的建议是将您的gotoCoffee功能更新为:

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

请注意,我将您的 console.log 行移至 setState 中的回调函数,以便在 AFTER 状态更新之前不会触发它。任何时候使用类组件并需要在更新状态后立即执行某些操作时,请使用回调函数。