Reputation: 640
I am having difficulties implementing a piece of React code that fetches and renders information from localStorage.
I have a gallery of thumbnail pictures (components) that upon a click, trigger a function that fetches information from a db for that particular picture and stores the data in localStorage. It also redirects the user to the ShowTale component where I display information about the picture.
class Tale extends Component {
handleClick(){
const pictureId = this.props._id;
this.props.fetchTale(pictureId);
}
render() {
const {_id, title, story, picture} = this.props;
return (
<div className="col-md-2 col-sm-6">
<div className="thumbnail">
<img src={picture} />
<div className="caption">
<h4>{title}</h4>
</div>
<p>
<Link onClick={this.handleClick.bind(this)} to="showTale" className="btn btn-primary">More Info</Link>
</p>
</div>
</div>
)
}
};
export default connect(null, actions)(Tale);
I set the data via the following action:
export function fetchTale(id){
return function(dispatch){
axios.get(`${ROOT_URL}/tale`, {params: {id: id}}).then(function(response) {
localStorage.setItem('fishTail', JSON.stringify(response.data));
})
}
};
The problem lies in that the ShowTale component, below, does not render the correct data. It renders the correct data on the first instance upon starting the application, but on subsequent requests, it renders the previous data. For example: I'll start the app, click on picture 1 renders 1, click on picture 2 renders 1, click on picture 3 renders 2, and so on. The data on localStorage is being correctly updates, but it appears the component is grabbing the data from localStorage before it is updated by the action.
class ShowTale extends Component {
constructor(props){
super(props)
this.state = {tale: JSON.parse(localStorage.getItem('fishTail'))}
}
componentWillMount(){
this.setState = JSON.parse(localStorage.getItem('fishTail'));
}
renderTale(){
const tale = this.state.tale;
console.log('the tale: ', tale);
const {title, story, picture, author} = tale;
return (
<div className="thumbnail">
<img className="image-responsive" src={picture}/>
<div className="caption-full">
<h4>{title}</h4>
<p>{story}</p>
<p><em>Submitted by: {author}</em></p>
</div>
</div>
)
}
render() {
return(
<div className="container showTale">
<div className="row">
<div className="col-sm-12">
{this.renderTale()}
</div>
</div>
</div>
)
}
};
export default ShowTale;
Any assistance with getting the pictures to show in sync with the data in localStorage will be greatly appreciated!
Upvotes: 1
Views: 6182
Reputation: 675
I'm using JSX so this may look weird to you. You could put all the elements that need to change, in the state of your parent. Then the child component will be dumb, and just handle the content as it changes from the Tale parent component example:
class Tale extends Component {
// Parent Tale component handles fetching and setting state.
constructor(props){
super(props)
this.state = {
title:'',
story:'',
picture: Null,
author: ''
}
}
componentWillMount(){
this.fetch_info()
}
fetch_info(){
newObj = JSON.parse(localStorage.getItem('fishTail'))
setState({
title: newObj.title,
story: newObj.story,
picture: newObj.picture,
author: newObj.title
});
}
render() {
return(
<div className="container showTale">
<div className="row">
<div className="col-sm-12">
<ShowTale
title={this.state.title}
story={this.state.story}
picture={this.state.picture}
author={this.state.author} />
</div>
</div>
</div>
)
}
};
class ShowTale extends Component {
// Child ShowTale receives Props.
constructor(props){
super(props)
}
render(){
<div className="thumbnail">
<img className="image-responsive" src={this.props.picture}/>
<div className="caption-full">
<h4>{this.props.title}</h4>
<p>{this.props.story}</p>
<p><em>Submitted by: {this.props.author}</em></p>
</div>
</div>
}
export default ShowTale;
If this doesn't work, look at passing in a function to setState. Here is an example from the documentation.
Hope this example helps -- sorry it is in JSX!
Upvotes: 1