Long Phan Long Phan - 1 month ago 10
React JSX Question

Should i be using forceUpdate() or finding another way to rerender React component

I have this component and I would like to rerender after my api call. I cant figure out why after api call of getWinks, winks-count does update but not on the view unless I refresh. Should I not be using this.forceUpdate(). Please advise and any criticism is welcome.

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>
)
}
}


Parent component:

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>
)

Answer

Generally, you should never have to use forceUpdate(). Instead, you should be using this.setState() to update the data, as it will make your component re-render automatically using the new data.

It's not clear from your example, but assuming that the response parameter in the getWinks() method contains the updated products, it should be used to update the state.

But since you get the initial products from the parent, using props, you need to pass the updated products back to the parent and let it run this.setState({ products }) (which will trigger a re-render, and in turn cause the component you show to re-render with the new data).

Comments