Почему компонент 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(обновление, [обратный вызов]).