【问题标题】:Why React component doesn't render?为什么 React 组件不渲染?
【发布时间】:2018-01-09 04:58:07
【问题描述】:

我正在制作简单的反应应用程序。我需要下订单。对于该订单,我需要所有用户和产品的列表。我有 CreateOrder 组件,它的 state - usersproducts 中有 2 个变量。这是构造函数

this.state.orders = OrderStore.getState()
this.state.products = ProductStore.getState()
this.state.users = UserStore.getState()
this.onOrderChange = this.onOrderChange.bind(this)
this.onProductChange = this.onProductChange.bind(this)
this.onUserChange = this.onUserChange.bind(this)
this.createOrder = this.createOrder.bind(this)
this.renderProducts = this.renderProducts.bind(this)
this.renderUsers = this.renderUsers.bind(this)
this.users = []
this.products = []

如您所见,我使用了 3 个商店,因此使用了 3 个函数来更新这些商店。之后,我有 2 个用于渲染产品和用户的功能。这些函数从它们各自的变量中获取所有产品和用户,并创建一个option 标签数组以供<select> 使用。这些数组存储在this.usersthis.products 中,以便我可以使用它们。

这是renderUsersrenderProducts中的代码

renderUsers(){
    this.users = this.state.users.users.map((user, i) => (
        <option
          key={i + 1}
          value={user}>
          {user.username}
        </option>
      )
    )
    console.log(this.users)
  }
  renderProducts(){
    this.products = this.state.products.products.map((product, i) => (
        <option
          key={i + 1}
          value={product}>
          {product.name}
        </option>
      )
    )
    console.log(this.products)
  }

我看不出两者之间有多大区别。在制作完数组并用option 标签填充后,我使用console.log 来查看结果。这是一张实际的照片

如您所见,有 2 个对象数组,每个对象都是预期的反应组件。

当我渲染CreateOrder 时,我使用this.productsthis.users 进行渲染,起初它们是空的。然后,当商店发生变化时(它们被所有产品和用户填充),函数renderUsersrenderProducts 被执行,因此数组被数据填充。发生这种情况时,我希望视图会更新。

现在的问题 - 当这种情况发生并且 this.products 正在更新时,视图实际上发生了变化,并且实际上更新了所有产品的列表。但是 - 使用相同的逻辑和相同的功能和代码 - 用户没有被更新。他们保持不变。即使我将它们作为数组中的元素并在render 中调用此数组,它们也没有被更新。

在这里添加一些信息是我的整个CreateOrder 文件。

 /**
 * Created by PC on 01-Aug-17.
 */
import React from 'react'
import OrderActions from '../actions/OrderActions'
import ProductActions from '../actions/ProductActions'
import ProductStore from '../stores/ProductStore'
import UserActions from '../actions/UserActions'
import UserStore from '../stores/UserStore'
import OrderStore from '../stores/OrderStore'

import Select from './sub-components/SelectComponent'
import Input from './sub-components/InputComponent'

export default class CreateOrder extends React.Component {
  constructor (props) {
    super(props)
    this.state = {}
    this.state.orders = OrderStore.getState()
    this.state.products = ProductStore.getState()
    this.state.users = UserStore.getState()
    this.onOrderChange = this.onOrderChange.bind(this)
    this.onProductChange = this.onProductChange.bind(this)
    this.onUserChange = this.onUserChange.bind(this)
    this.createOrder = this.createOrder.bind(this)
    this.renderProducts = this.renderProducts.bind(this)
    this.renderUsers = this.renderUsers.bind(this)
    this.users = []
    this.products = []
  }
  componentDidMount () {
    OrderStore.listen(this.onOrderChange)
    ProductStore.listen(this.onProductChange)
    UserStore.listen(this.onUserChange)
    ProductActions.getAllProducts()
    UserActions.getAllUsers()

  }
  componentWillUnmount () {
    OrderStore.unlisten(this.onOrderChange)
    UserStore.unlisten(this.onUserChange)
    ProductStore.unlisten(this.onProductChange)

  }
  onOrderChange (state) {
    this.setState({orders:state})
  }
  onProductChange(state) {
    this.setState({products:state})
    this.renderProducts()
  }
  onUserChange(state){
    this.setState({users:state})
    this.renderUsers()
  }
  createOrder (event) {
    event.preventDefault()

      let data = {}
      data['username'] = this.state.orders.username
      data['productName'] = this.state.orders.product.name
      data['productPrice'] = this.state.orders.product.price
      data['quantity'] = this.state.orders.quantity

      OrderActions.addOrder(data)
  }
  renderUsers(){
    this.users = this.state.users.users.map((user, i) => (
        <option
          key={i + 1}
          value={user}>
          {user.username}
        </option>
      )
    )
    console.log(this.users)
  }
  renderProducts(){
    this.products = this.state.products.products.map((product, i) => (
        <option
          key={i + 1}
          value={product}>
          {product.name}
        </option>
      )
    )
    console.log(this.products)
  }
  render () {

    return (
      <div>
        <div className='has-error'>
          {this.state.orders.error}
        </div>
        <div className='has-success'>
          {this.state.orders.success}
        </div>
        <form>
          <select>{this.users}</select>
          <select>{this.products}</select>

          <div className="inputField">
            <label htmlFor='title'>Quantity</label>
            <Input
              type='number'
              name='price'
              id='price'
              placeholder='Price'
              onChange={OrderActions.handleQuantityChange}
              value={this.state.quantity}/>
          </div>
          <input type='submit' onClick={this.createOrder.bind(this)} value='Create Order'/>
        </form>
      </div>
    )
  }
}

【问题讨论】:

    标签: javascript reactjs reactjs-flux react-alt


    【解决方案1】:

    setState 是异步的。尝试将您的 this.renderUsers(); 放入 componentWillUpdate 生命周期方法中。

    componentWillUpdate() 在接收到新的 props 或 state 时在渲染之前立即调用。以此为契机,在更新发生之前进行准备。初始渲染不调用此方法。

    您也可以使用setState(updater, [callback])callback 参数。

    【讨论】:

      【解决方案2】:

      我不确定问题的实际原因,但我认为这与 setState 的异步行为有关,我们不能指望在 setState 之后更新状态值。

      查看此answer,了解有关 setState 异步行为的更多详细信息。

      解决方案:

      将ui组件存储在状态变量或全局变量中不是一个好主意,所有的ui逻辑都应该在render方法中,因此不要将选项存储在全局变量中,而是直接从该函数返回。

      每当我们执行setState 时,react 都会重新渲染组件并使用新数据更新 ui。

      Step1 - 使用这些方法,移除另一个函数调用:

      onProductChange(state) {
          this.setState({products:state})
      }
      
      onUserChange(state){
          this.setState({users:state})
      }
      

      Step2 - 使用这些方法来呈现选项:

      renderUsers(){
          if(!this.state.users.users) return null;
      
          return this.state.users.users.map((user, i) => (
              <option
                key={i + 1}
                value={user}>
                {user.username}
              </option>
            )
          )
      }
      
      renderProducts(){
          if(!this.state.products.products) return null;
      
          return this.state.products.products.map((product, i) => (
              <option
                key={i + 1}
                value={product}>
                {product.name}
              </option>
            )
          )
      }
      

      Step3 - 从渲染中调用这些函数来创建选项:

       <select>{this.renderUsers()}</select>
       <select>{this.renderProducts()}</select>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-07
        • 2020-09-15
        • 2016-06-21
        相关资源
        最近更新 更多