为什么 React 组件不渲染?
Why React component doesn't render?
我正在制作简单的 React 应用程序。我需要下订单。对于该订单,我需要所有用户的列表,并且 products.I 具有 CreateOrder
组件,其 state
- users
和 products
中有 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.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>
)
}
}
setState
是异步的。尝试将您的 this.renderUsers();
放入 componentWillUpdate
生命周期方法中。
componentWillUpdate() is invoked immediately before rendering when new props or state are being received. Use this as an opportunity to perform preparation before an update occurs. This method is not called for the initial render.
您也可以使用 setState(updater, [callback]) 的 callback
参数。
我不确定问题的真正原因,但我认为这与 setState 的异步行为有关,我们不能期望在 setState 之后立即更新状态值。
查看此 以获取有关 setState 异步行为的更多详细信息。
解法:
将 ui 组件存储在状态变量或全局变量中不是一个好主意,所有 ui 逻辑都应该在 render 方法中,所以不要将选项存储在全局变量中,直接return 来自那个函数。
每当我们做 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>
我正在制作简单的 React 应用程序。我需要下订单。对于该订单,我需要所有用户的列表,并且 products.I 具有 CreateOrder
组件,其 state
- users
和 products
中有 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.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
来查看结果。这是一张实际的图片
当我渲染 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>
)
}
}
setState
是异步的。尝试将您的 this.renderUsers();
放入 componentWillUpdate
生命周期方法中。
componentWillUpdate() is invoked immediately before rendering when new props or state are being received. Use this as an opportunity to perform preparation before an update occurs. This method is not called for the initial render.
您也可以使用 setState(updater, [callback]) 的 callback
参数。
我不确定问题的真正原因,但我认为这与 setState 的异步行为有关,我们不能期望在 setState 之后立即更新状态值。
查看此
解法:
将 ui 组件存储在状态变量或全局变量中不是一个好主意,所有 ui 逻辑都应该在 render 方法中,所以不要将选项存储在全局变量中,直接return 来自那个函数。
每当我们做 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>