我应该使用 forceUpdate() 还是寻找另一种方法来重新渲染 React 组件
Should i be using forceUpdate() or finding another way to rerender React component
我有这个组件,我想在 api 调用后重新呈现。我无法弄清楚为什么在 api 调用 getWinks 之后,winks-count 会更新但不在视图上,除非我刷新。我不应该使用 this.forceUpdate() 吗?欢迎指教,欢迎批评
export default class Winks extends Component {
constructor (props) {
super(props)
this.insertDecimal = this.insertDecimal.bind(this)
this.state = ({
user:cookie.load('user',
)})
console.log(this.state)
this.httpHandler = axios.create({
baseURL: 'localhost:3000',
headers: {
'Authorization': this.state.user.token
}
})
}
insertDecimal(num) {
var num = (num / 100).toFixed(2);
return '$' + num
}
getWinks (itemId) {
this.httpHandler.post("/users/" + this.state.user.id + "/winks", {
user_id:this.state.user.id,
wink: {
product_id:itemId
}
}).then(function (response){
this.forceUpdate()
}.bind(this))
}
render () {
var listItems = this.props.products.map(function(item, index,) {
var wink = item.attributes
if (index % 5 ===0) {
return (
<Col lg={2} md={4} sm={4} xs={6}>
<div className="item">
<img className='img-responsive' src={wink["image-url"]}></img>
<div className="item-meta">
<span className="name">{wink.name}</span>
<span className="site"> Bloomingdales.com</span>
<div className="rate">
<span className="old">{this.insertDecimal(wink.price)}</span>
<span className="new">{this.insertDecimal(wink["sale-price"])}</span>
</div>
<div className="like">
<i onClick={()=>this.getWinks(item.id)} className="fa fa-heart"></i>
<span>{wink["winks-count"]}</span>
</div>
</div>
</div>
</Col>
)
}
else {
return (
<Col lg={2} md={4} sm={4} xs={6}>
<div className="item">
<img className='img-responsive' src={wink["image-url"]}></img>
<div className="item-meta">
<span className="name">{wink.name}</span>
<span className="site"> Bloomingdales.com</span>
<div className="rate">
<span className="old">{this.insertDecimal(wink.price)}</span>
<span className="new">{this.insertDecimal(wink["sale-price"])}</span>
</div>
<div className="like">
<i onClick={()=>this.getWinks(item.id)} className="fa fa-heart"></i>
<span>{wink["winks-count"]}</span>
</div>
</div>
</div>
</Col>
)
}
}.bind(this));
return (
<Row className="item-row">
{listItems}
</Row>
)
}
}
父组件:
export default class AllItems extends Component {
constructor () {
super()
this.state=({ user: cookie.load('user')})
this.httpHandler = axios.create({
baseURL: 'localhost:3000',
headers: {
'Authorization': this.state.user.token
}
})
}
componentWillMount() {
this.httpHandler('/products/')
.then(function (response) {
this.setState({ winks: response.data.data})
}.bind(this))
}
render() {
return (
<Grid>
<div className="item-wrapper">
<Row>
<h1 className="text-center">All Items</h1>
</Row>
<Row>
<Col xs={2}>
<div className="item-sidebar-wrapper">
<div className="sort">
<Sort />
</div>
<div className="category">
<Category />
</div>
<div className="price">
<Price />
</div>
<div className="size">
<Size />
</div>
<div className="color">
<Color />
</div>
<div className="brand">
<Brand />
</div>
<div className="stores">
<Stores />
</div>
</div>
</Col>
<Col xs={10}>
<Winks products={this.state.winks} />
</Col>
</Row>
</div>
</Grid>
)
使用 state
。比如说,使用状态 loader
,当您调用 httpHandler
时它应该设置为 true
,当异步操作完成时它应该设置为 false
。这样,更改状态将重新渲染组件而无需任何 forceupdate()
像这样。
getWinks (itemId) {
this.setState({loading: true})
this.httpHandler.post("/users/" + this.state.user.id + "/winks", {
user_id:this.state.user.id,
wink: {
product_id:itemId
}
}).then(function (response){
this.setState({loading: false})
}.bind(this))
}
通常,您永远不必使用 forceUpdate()
。相反,您应该使用 this.setState()
来更新数据,因为它会让您的组件使用新数据自动重新渲染。
从你的例子看不清楚,但假设getWinks()
方法中的response
参数包含更新的产品,它应该用于更新状态。
但是由于是从父级获取初始产品,使用道具,需要将更新后的产品传回父级,让它运行this.setState({ products })
(这会触发重新渲染,然后导致您显示的组件使用新数据重新渲染)。
你的组件不会重新渲染,因为你没有改变它的状态或道具,所以它没有任何要更新的东西,这就是反应的工作原理。
在您的代码中,您发送了 POST 请求,但您没有对响应执行任何操作。您能解释一下这个请求的作用吗?
您的组件是 props
和 state
的函数。因此,只要它们发生变化,您的组件就会再次呈现。
如果传递给组件的 state
或 props
从调用组件或任何父组件上的 setState(...)
更改,则您的组件将再次呈现。因此,您唯一会使用 forceupdate()
的情况是当您需要组件作为其他功能呈现时。
例如,假设您有一个正在传递属性 elapsed
和 runningSince
的 Timer
组件。 Timer
组件将根据 elapsed
、runningSince
和 Date.now()
计算向用户显示的时间。但是,除非用户单击开始或停止按钮,否则 elapsed
和 runningSince
不会更改。但是 Timer
组件不会显示实时计时器,因为没有任何东西会触发它的 render
功能。要解决此问题,您可以添加一个更新间隔,例如每隔 50 ms
调用 forceupdate()
。
我有这个组件,我想在 api 调用后重新呈现。我无法弄清楚为什么在 api 调用 getWinks 之后,winks-count 会更新但不在视图上,除非我刷新。我不应该使用 this.forceUpdate() 吗?欢迎指教,欢迎批评
export default class Winks extends Component {
constructor (props) {
super(props)
this.insertDecimal = this.insertDecimal.bind(this)
this.state = ({
user:cookie.load('user',
)})
console.log(this.state)
this.httpHandler = axios.create({
baseURL: 'localhost:3000',
headers: {
'Authorization': this.state.user.token
}
})
}
insertDecimal(num) {
var num = (num / 100).toFixed(2);
return '$' + num
}
getWinks (itemId) {
this.httpHandler.post("/users/" + this.state.user.id + "/winks", {
user_id:this.state.user.id,
wink: {
product_id:itemId
}
}).then(function (response){
this.forceUpdate()
}.bind(this))
}
render () {
var listItems = this.props.products.map(function(item, index,) {
var wink = item.attributes
if (index % 5 ===0) {
return (
<Col lg={2} md={4} sm={4} xs={6}>
<div className="item">
<img className='img-responsive' src={wink["image-url"]}></img>
<div className="item-meta">
<span className="name">{wink.name}</span>
<span className="site"> Bloomingdales.com</span>
<div className="rate">
<span className="old">{this.insertDecimal(wink.price)}</span>
<span className="new">{this.insertDecimal(wink["sale-price"])}</span>
</div>
<div className="like">
<i onClick={()=>this.getWinks(item.id)} className="fa fa-heart"></i>
<span>{wink["winks-count"]}</span>
</div>
</div>
</div>
</Col>
)
}
else {
return (
<Col lg={2} md={4} sm={4} xs={6}>
<div className="item">
<img className='img-responsive' src={wink["image-url"]}></img>
<div className="item-meta">
<span className="name">{wink.name}</span>
<span className="site"> Bloomingdales.com</span>
<div className="rate">
<span className="old">{this.insertDecimal(wink.price)}</span>
<span className="new">{this.insertDecimal(wink["sale-price"])}</span>
</div>
<div className="like">
<i onClick={()=>this.getWinks(item.id)} className="fa fa-heart"></i>
<span>{wink["winks-count"]}</span>
</div>
</div>
</div>
</Col>
)
}
}.bind(this));
return (
<Row className="item-row">
{listItems}
</Row>
)
}
}
父组件:
export default class AllItems extends Component {
constructor () {
super()
this.state=({ user: cookie.load('user')})
this.httpHandler = axios.create({
baseURL: 'localhost:3000',
headers: {
'Authorization': this.state.user.token
}
})
}
componentWillMount() {
this.httpHandler('/products/')
.then(function (response) {
this.setState({ winks: response.data.data})
}.bind(this))
}
render() {
return (
<Grid>
<div className="item-wrapper">
<Row>
<h1 className="text-center">All Items</h1>
</Row>
<Row>
<Col xs={2}>
<div className="item-sidebar-wrapper">
<div className="sort">
<Sort />
</div>
<div className="category">
<Category />
</div>
<div className="price">
<Price />
</div>
<div className="size">
<Size />
</div>
<div className="color">
<Color />
</div>
<div className="brand">
<Brand />
</div>
<div className="stores">
<Stores />
</div>
</div>
</Col>
<Col xs={10}>
<Winks products={this.state.winks} />
</Col>
</Row>
</div>
</Grid>
)
使用 state
。比如说,使用状态 loader
,当您调用 httpHandler
时它应该设置为 true
,当异步操作完成时它应该设置为 false
。这样,更改状态将重新渲染组件而无需任何 forceupdate()
像这样。
getWinks (itemId) {
this.setState({loading: true})
this.httpHandler.post("/users/" + this.state.user.id + "/winks", {
user_id:this.state.user.id,
wink: {
product_id:itemId
}
}).then(function (response){
this.setState({loading: false})
}.bind(this))
}
通常,您永远不必使用 forceUpdate()
。相反,您应该使用 this.setState()
来更新数据,因为它会让您的组件使用新数据自动重新渲染。
从你的例子看不清楚,但假设getWinks()
方法中的response
参数包含更新的产品,它应该用于更新状态。
但是由于是从父级获取初始产品,使用道具,需要将更新后的产品传回父级,让它运行this.setState({ products })
(这会触发重新渲染,然后导致您显示的组件使用新数据重新渲染)。
你的组件不会重新渲染,因为你没有改变它的状态或道具,所以它没有任何要更新的东西,这就是反应的工作原理。
在您的代码中,您发送了 POST 请求,但您没有对响应执行任何操作。您能解释一下这个请求的作用吗?
您的组件是 props
和 state
的函数。因此,只要它们发生变化,您的组件就会再次呈现。
如果传递给组件的 state
或 props
从调用组件或任何父组件上的 setState(...)
更改,则您的组件将再次呈现。因此,您唯一会使用 forceupdate()
的情况是当您需要组件作为其他功能呈现时。
例如,假设您有一个正在传递属性 elapsed
和 runningSince
的 Timer
组件。 Timer
组件将根据 elapsed
、runningSince
和 Date.now()
计算向用户显示的时间。但是,除非用户单击开始或停止按钮,否则 elapsed
和 runningSince
不会更改。但是 Timer
组件不会显示实时计时器,因为没有任何东西会触发它的 render
功能。要解决此问题,您可以添加一个更新间隔,例如每隔 50 ms
调用 forceupdate()
。