Почему компонент React не рендерится?

Я делаю простое приложение реагировать. Мне нужно сделать заказ. Для этого заказа мне нужен список всех пользователей и продуктов. У меня есть CreateOrder компонент, который имеет 2 переменные в state - users а также products, Вот конструктор

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.users а также this.products так что я могу их использовать.

Вот код в renderUsers а также renderProducts

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.products а также this.users быть оказанным, и сначала они пусты. Затем, когда что-то меняется в магазинах (они заполнены всеми продуктами и пользователями), функции renderUsers а также renderProducts выполняются и, следовательно, массивы заполнены данными. Когда это произойдет, я ожидаю, что представление будет обновлено.

Теперь проблема - когда это происходит и 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 ответа

Решение

Я не уверен в истинной причине проблемы, но я думаю, что это связано с асинхронным поведением setState, мы не можем ожидать обновленное значение состояния сразу после setState.

Проверьте этот ответ для более подробной информации об асинхронном поведении setState.

Решение:

Хранить компонент пользовательского интерфейса в переменной состояния или в глобальной переменной не очень хорошая идея, вся логика пользовательского интерфейса должна быть внутри метода рендеринга, поэтому вместо сохранения параметров в глобальной переменной следует напрямую возвращаться из этой функции.

Всякий раз, когда мы делаем setState "Реакция" выполнит повторную визуализацию компонента и обновит пользовательский интерфейс новыми данными.

Шаг 1 - Используйте эти методы, удалил еще один вызов функции:

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

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

Шаг 2 - Используйте эти методы для визуализации параметров:

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>

setState асинхронный Попробуйте положить свой this.renderUsers(); в componentWillUpdate метод жизненного цикла.

componentWillUpdate () вызывается непосредственно перед рендерингом при получении новых реквизитов или состояний. Используйте это как возможность выполнить подготовку до того, как произойдет обновление. Этот метод не вызывается для начального рендеринга.

Вы также можете использовать callback аргумент setState(обновление, [обратный вызов]).

Другие вопросы по тегам