为什么React组件不呈现?

时间:2017-08-02 06:17:16

标签: javascript reactjs reactjs-flux react-alt

我正在制作简单的反应应用。我需要下订单。对于该订单,我需要一个包含所有用户和产品的列表。我的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查看结果。这是实际

的图片

enter image description here 如您所见,有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>
    )
  }
}

2 个答案:

答案 0 :(得分:1)

我不确定问题的实际原因,但我认为这与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>
      )
    )
}

第3步 - 从渲染中调用这些函数以创建选项:

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

答案 1 :(得分:0)

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

  

在呈现新的道具或状态时,会立即调用componentWillUpdate()。使用此作为在更新发生之前执行准备的机会。初始渲染不会调用此方法。

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