jansmolders86 jansmolders86 - 3 months ago 26
Javascript Question

React Router: this.props.params not updated after Link click

I'm building a simple react app with a sidebar. from it, I want to swap out the various categories of the app.

My router looks like this:

<Route path={path} component={App}>
<IndexRoute component={HomeView} />
<Route path="/" component={HomeView} />
<Route path="/manage" component={LoggedInView} />
<Route path="/search/:topic" component={SearchView} />
<Route path="/c/:category" component={CategoryView} />
<Route path="*" component={ErrorView} type="404"/>
</Route>


In the sidebar I have a link like this:

<Link to={{ pathname: '/c/'+el.urlkey}} activeClassName="active"{el.title}</Link>


Finally in the CategoryView I have this variable:

let queryParam = this.props.params.category;


When I click the Link, the url in the urlbar changes, but the category doesn't. When I click it again, the category changes as well.

If I log the 'queryParam ', I see that the first time I click, it returns the same value. only after the second click does it change.

Why isn't it changing on the first click? I've also tried routing programmatically using

this.props.router.push(url);


But the issue still occurs.
Any help is greatly appreciated!


  • EDIT



This is the code for the Categoryview



@pureRender
class Category extends Component {

constructor(props) {
super(props);
this.state = {
activeCategoryName: '',
activeCategory: {},
availableTopics: {},
language : {},
notFound: false,
isEmpty: false,
isLoading: true,
showAdminModal: this.showAdminModal.bind(this)
};
}

showAdminModal(){
this.props.modalHandler("AdminTopic", this.state.activeCategoryName);
}

componentWillReceiveProps() {
this.showCategory();
}

componentWillMount(){
this.showCategory();
}

showCategory(){
const self = this;
let queryParam = this.props.params.category;
const availableCategories = this.props.categories;
let matched = false;

const count = availableCategories.length - 1;
if(count === -1){
this.setState({
notFound: true
});
} else {
filter(availableCategories, function (el, index) {
const categoryTitle = el.urlkey.toLowerCase();
const activeLocale = self.props.activeLocale;
let title = null;
if (queryParam !== undefined) {
title = queryParam.toLowerCase();
}

if(categoryTitle === title && el.language === activeLocale){
matched = true;
self.setState({
activeCategoryName: categoryTitle,
activeCategory: el,
notFound: false,
isLoading: false,
isEmpty: false
});
} else if(index === count && !matched){
self.setState({
isEmpty: true,
isLoading: false
});
}
});
}
}

render() {
const activeCategory = this.state.activeCategory;
let adminButton = '';
if(this.props.isAdmin){
adminButton = (
<button className={s.adminButton} onClick={this.state.showAdminModal}>
<div className="pull-left">Add Topic</div>
<div className="pull-right">+</div>
</button>
);
}
if(this.state.isLoading){
return null;
}
if(this.state.isEmpty){
return (
<ErrorView reason="empty" isAdmin={this.props.isAdmin} modalHandler={this.props.modalHandler}/>
);
} else if(this.state.notFound){
return (
<ErrorView reason="404"/>
);
} else if(!this.state.notFound && !this.state.isEmpty){
return (
<div>
<Banner key={activeCategory.title}
isAdmin={this.props.isAdmin}
activeCategory={activeCategory}
title={activeCategory.title}
activeLocale={this.props.activeLocale}
translate={false}
description={activeCategory.description}
modalHandler={this.props.modalHandler}
image={activeCategory.image}/>

<div style={{minHeight:800}}>
<Topic key={activeCategory}
activeCategory={activeCategory}
single={false}
modalHandler={this.props.modalHandler}
isAdmin={this.props.isAdmin}/>
{adminButton}
</div>
</div>
);
}
}
}

export default withStyles(Category, s);




Answer

The reason you're seeing the old data when you click the second time, is because componentWillReceiveProps executes before this.props is updated with that information. Update the method to do this instead:

componentWillReceiveProps(nextProps) {
  this.showCategory(nextProps);
}

showCategory(props) {
  let queryParam = props.params.category;
  // etc
}

In terms of the first one not showing up, try passing this.props (with the changes above) in a componentDidMount instead of componentWillMount. I realize this causes a new render to run, but I wonder if the props aren't initialized yet. If that doesn't fix it, I think you need to debug the details in your filter function, and see if setState is being called.

Comments