Which React Lifecycle Methods for controlling state of buttons (enabled/disabled)? - javascript

I have SearchBar Component like so:
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = {
term: '',
page: 1,
prevButton: false,
nextButton: true,
};
And buttons like so:
<div>
<button
className="btn btn-secondary"
onClick={this.handlePrev}
disabled={!this.state.prevButton}
>
Prev Page
</button>
<span className="SearchBar-page-numbers">{this.state.page}</span>
<button
className="btn btn-secondary"
onClick={this.handleNext}
disabled={!this.state.nextButton}
>
Next Page
</button>
</div>
Now I want to add code that for every component update will check which page on the user is.
-
So if the user is on page number one (this.state.page === 1) this.state.prevButton should be always false, but for every other page this.state.prevButton should be always true.
this.state.nextButton should be false only when this.state.page === 10
I need navigation between page 1 to 10 only.
-
Which React Lifecycle Methods would be sufficient for that functionality?
I tried something like that but it is no good, it is unclear, messy and doesn't work...
componentDidUpdate(prevProps) {
if (this.props !== prevProps) {
if (this.state.page === 1) {
this.setState({ prevButton: false });
}
if (this.state.page !== 1) {
this.setState({ prevButton: true });
}
}
}
UPDATE:
If you see better way of doing this, please share you thoughts!
Full code of that component:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import {
wakeUpHerokuServerFromSleep,
fetchRecipesAndPage,
loadRecipes,
showClickedInfo,
addLocalStorageToFavoritesList,
} from '../../actions/';
import './style.css';
import ButtonSearch from '../../components/ButtonSearch';
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = {
term: '',
page: 1,
prevButton: false,
nextButton: true,
};
this.handlePrev = this.handlePrev.bind(this);
this.handleNext = this.handleNext.bind(this);
this.handleInputChange = this.handleInputChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
componentDidMount() {
this.props.wakeUpHerokuServerFromSleep();
const localStorageData = JSON.parse(
localStorage.getItem('lastSavedFavourites')
);
if (localStorageData) {
this.props.addLocalStorageToFavoritesList(localStorageData);
}
}
componentDidUpdate(prevProps, prevState) {
if (this.props !== prevProps) {
this.setState({ term: this.props.showClickedInfoFromStore });
this.checker(this.props);
}
const { page } = this.state;
if (prevState.page !== page) {
this.setState({ prevButton: page !== 1 });
}
}
// If some ingredient was manually selected
// go to page 1 of that ingredient
checker(properties) {
if (properties.manualSelectionFromStore) {
this.setState({ page: 1 });
}
}
// If input was changed go to page 1
handleInputChange(event) {
this.setState({ page: 1 });
this.setState({ term: event.target.value });
}
// After submit, go to page 1 and fetch data
handleSubmit(event) {
this.setState({ page: 1 });
if (this.state.term === '') {
event.preventDefault();
this.props.showClickedInfo('');
} else {
event.preventDefault();
this.props.fetchRecipesAndPage(this.state.term, 1);
this.props.showClickedInfo(this.state.term);
}
}
handlePrev() {
let newPage = this.state.page - 1;
if (newPage <= 0) {
newPage = 1;
}
this.setState({ page: newPage });
this.props.loadRecipes(newPage);
}
handleNext() {
let newPage = this.state.page + 1;
if (newPage >= 10) {
newPage = 10;
}
this.setState({ page: newPage });
this.props.loadRecipes(newPage);
}
buttonsView() {
// Show navigation buttons (prev, next):
// If there is an error coming from server
// OR
// If current search isn't null AND app has found some data and successfully fetched it
if (
this.props.error ||
(this.props.currentSearchFromStore !== null &&
this.props.checkIfSomeDataWasFound)
) {
return (
<div>
<button
className="btn btn-secondary"
onClick={this.handlePrev}
disabled={!this.state.prevButton}
>
Prev Page
</button>
<span className="SearchBar-page-numbers">{this.state.page}</span>
<button
className="btn btn-secondary"
onClick={this.handleNext}
disabled={!this.state.nextButton}
>
Next Page
</button>
</div>
);
}
// Esle return just <div />
return <div />;
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit} className="SearchBar-input-group">
<input
className="form-control"
placeholder={this.props.showClickedInfoFromStore}
value={this.state.term}
onChange={this.handleInputChange}
/>
<ButtonSearch className="btn btn-secondary submit">
Search
</ButtonSearch>
</form>
<div className="SearchBar-pagination-buttonsView">
{this.buttonsView()}
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
error: state.error,
currentSearchFromStore: state.currentSearchTerm,
checkIfSomeDataWasFound: state.checkRecipesData,
showClickedInfoFromStore: state.showClickedInfo,
manualSelectionFromStore: state.manualSelection,
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(
{
wakeUpHerokuServerFromSleep,
fetchRecipesAndPage,
loadRecipes,
showClickedInfo,
addLocalStorageToFavoritesList,
},
dispatch
);
}
export default connect(mapStateToProps, mapDispatchToProps)(SearchBar);

Alternately, you could just disable the buttons based on page as follows:
const { page } = this.state;
<div>
<button
className="btn btn-secondary"
onClick={this.handlePrev}
disabled={page === 1}
>
Prev Page
</button>
<span className="SearchBar-page-numbers">{this.state.page}</span>
<button
className="btn btn-secondary"
onClick={this.handleNext}
disabled={page === x}
>
Next Page
</button>
</div>
I'm not sure how you are disabling the next button, but subsitute x above with the number of pages.

Regarding your 'which lifecycle method' question, I would suggest using componentWillReceiveProps if you're checking whether something should re-render based on props changes. You'd compare this.props to nextProps (pass in nextProps as the argument to componentWillReceiveProps) in that method, and perform an action based on that.
However, if you're just trying to determine whether to enable/disable buttons, you could use the following in the 'disabled' property of the buttons.
i.e. for 'previous' button
disabled={this.state.page === 1}
and for 'next' button
disabled={this.state.page === 10}

Related

React suggestions Input setting state

im prety new to React and im trying to use an autocomplete input. Im having problems getting the value from it and clearing the input values after submitting. Any help would be greatly appretiated.
import React, { Component, Fragment } from "react";
import PropTypes from "prop-types";
import "../AutoComplete/styles.css"
class Autocomplete extends Component {
static propTypes = {
suggestions: PropTypes.instanceOf(Array)
};
static defaultProps = {
suggestions: [],
};
constructor(props) {
super(props);
this.state = {
// The active selection's index
activeSuggestion: 0,
// The suggestions that match the user's input
filteredSuggestions: [],
// Whether or not the suggestion list is shown
showSuggestions: false,
// What the user has entered
userInput: this.props.value ? this.props.value : "",
};
}
//Order by 'code'
generateSortFn(prop, reverse) {
return function (a, b) {
if (a[prop] < b[prop]) return reverse ? -1 : 1;
if (a[prop] > b[prop]) return reverse ? 1 : -1;
return 0;
};
}
onChange = e => {
const { suggestions } = this.props;
const userInput = e.currentTarget.value;
// Filter our suggestions that don't contain the user's input
const filteredSuggestions = suggestions.sort(this.generateSortFn('code', true)).filter(
(suggestion, i) => {
let aux = suggestion.descrp+"- "+suggestion.code
return aux.toLowerCase().indexOf(userInput.toLowerCase()) > -1
}
);
this.setState({
activeSuggestion: 0,
filteredSuggestions,
showSuggestions: true,
userInput: e.currentTarget.value
});
};
onClick = e => {
this.setState({
activeSuggestion: 0,
filteredSuggestions: [],
showSuggestions: false,
userInput: e.currentTarget.innerText
});
};
onKeyDown = e => {
const { activeSuggestion, filteredSuggestions } = this.state;
// User pressed the enter key
if (e.keyCode === 13) {
this.setState({
activeSuggestion: 0,
showSuggestions: false,
userInput: filteredSuggestions[activeSuggestion].code+" - "+filteredSuggestions[activeSuggestion].descrp
});
}
// User pressed the up arrow
else if (e.keyCode === 38) {
if (activeSuggestion === 0) {
return;
}
this.setState({ activeSuggestion: activeSuggestion - 1 });
}
// User pressed the down arrow
else if (e.keyCode === 40) {
if (activeSuggestion - 1 === filteredSuggestions.length) {
return;
}
this.setState({ activeSuggestion: activeSuggestion + 1 });
}
};
render() {
const {
onChange,
onClick,
onKeyDown,
state: {
activeSuggestion,
filteredSuggestions,
showSuggestions,
userInput
}
} = this;
let suggestionsListComponent;
if (showSuggestions && userInput) {
if (filteredSuggestions.length) {
suggestionsListComponent = (
<ul className="suggestions">
{filteredSuggestions.map((suggestion, index) => {
let className="";
// Flag the active suggestion with a class
if (index === activeSuggestion) {
className = "suggestion-active";
}
return (
<li className={className} key={suggestion.code} onClick={onClick}>
{suggestion.code+" - "+suggestion.descrp}
</li>
);
})}
</ul>
);
} else {
suggestionsListComponent = (
<div className="no-suggestions">
<p>Sin sugerencias</p>
</div>
);
}
}
and the return (this is where i think im wrong)
return (
<Fragment>
<label htmlFor="autocomplete-input" className="autocompleteLabel">{this.props.label}</label>
<div className="centerInput">
<input
className="autocomplete-input"
type="text"
onChange={onChange}
onKeyDown={onKeyDown}
defaultValue={this.props.initState}
value= {/* this.props.value ? this.props.value : */ userInput}
placeholder={this.props.placeholder}
selection={this.setState(this.props.selection)}
/>
{suggestionsListComponent}
</div>
</Fragment>
);
}
}
export default Autocomplete;
What I want is to use this component in different pages, so im passing the "selection" prop and setting the state there.
The input is working correctly (searches, gets the value and shows/hide the helper perfectly). The problem is i cant reset this inputs clearing them, and i suspect the error is in here.
I get the following warning (even with it somewhat functioning)
Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.
This is the Component usage with useState:
<Autocomplete label='Out cost Center:' placeholder='Set the out cost center' suggestions={dataCostCenterHelper} selection={(text) => setOutCostCenter(text.userInput)} value={outCostCenter} />
and last this is how im tryin to clear the state that is set in "selection":
const clearData = async () => {
setOutCostCenter('-');
// other inputs with the same component
setOutVendor('-');
setOutRefNumber('-');
}
This gets called inside the function that handles the button submitting the form.
Thanks in advance!
Looking at the code you posted this line might be the problem:
selection={this.setState(this.props.selection)}
You are updating state directly inside the render method, this is not recommended.
Try using a selection prop or state field and update the prop inside a componenteDidMount life cycle
selection={this.state.selection}

React - timed action does not load specific component

What I want: when the timer hits 0 seconds, the app mounts one component and hides others.
What happens: nothing.
I'm working on React single page app. I'm having a problem with the behavior of the timer when it hits 0. I want it to hide the Questions and Timer components and show just the Results component. Right now, the logic is in timerZero, but I did try putting it in startTimer and/or clickStart, but none of those combinations worked.
I've also noticed that if you select answers after the timer hits 0, it will continue console logging "Time's up!" on every selection. Hitting submit after 0 seconds will still take you to the resultsDiv with the correct scores but does not hide the timer as instructed.
Repo: https://github.com/irene-rojas/pixar-react
App
import React, { Component } from 'react';
import './App.css';
import Timer from "./Timer";
import Questions from "./Questions/Questions.js";
import Results from "../src/Results";
class App extends Component {
state = {
totalTrue: 0,
totalFalse: 0,
showTimer: true,
showQuestions: false,
showResults: false,
}
clickStart = (event) => {
event.preventDefault();
console.log("start button clicked");
this.setState(
{showQuestions: true}
)
}
// submit button
handleFormSubmit = (event) => {
event.preventDefault();
console.log("submit button clicked");
this.setState(
{showResults: true,
showQuestions: false,
showTimer: false}
// timer still appears in resultsDiv
)
};
timerZero = () => {
if (this.state.timer === 0) {
this.setState(
{showResults: true,
showQuestions: false,
showTimer: false}
)
}
// nothing happens >:(
};
callbackHandlerFunction = ( selectedOption ) => {
const answerValue = selectedOption.value;
if (answerValue === true) {
this.setState({totalTrue: this.state.totalTrue + 1}, () => {
console.log(`New TotalTrue: ${this.state.totalTrue}`);
});
};
if (answerValue === false) {
this.setState({totalFalse: this.state.totalFalse + 1}, () => {
console.log(`New TotalFalse: ${this.state.totalFalse}`);
});
};
}
render() {
return (
<div className="parallax">
<div className="App">
<div className="wrapper">
<div className="headerDiv">
<h1>Pixar Trivia!</h1>
</div>
<div className="timerDiv">
<Timer
handleTimerClick={this.clickStart}
timeOut={this.timerZero}
/>
</div>
{this.state.showQuestions &&
<div className="questionSection">
<Questions
handleClickInParent={this.callbackHandlerFunction}
/>
<div>
<button onClick={this.handleFormSubmit}>Submit</button>
</div>
</div>
}
{this.state.showResults &&
<div className="resultsDiv">
<Results
totalTrue={this.state.totalTrue}
totalFalse={this.state.totalFalse}
/>
</div>
}
</div>
</div>
</div>
);
}
}
export default App;
Timer
import React, { Component } from 'react';
class Timer extends Component {
state = {
timer: 10
};
startTimer = (event) => {
this.timer = setInterval(() => this.setState({
timer: this.state.timer - 1}), 1000);
// onClick, load Questions
this.props.handleTimerClick(event);
};
stopTimer = () => {
clearInterval(this.timer);
console.log("Time's up!");
this.props.timeOut();
};
render() {
return (
<div className="Timer">
<div>{this.state.timer} seconds</div>
<button onClick={this.startTimer}>Start!</button>
{this.state.timer === 0 && this.stopTimer()}
</div>
);
}
}
export default Timer;
I found out what was wrong with your code, I'm just going to break up where the mistakes are.
App.js
// ...
/*
you were trying to read this.state.timer
which is not decalred in this component
*/
timerZero = () => this.setState(
{showResults: true,
showQuestions: false,
showTimer: false}
)
// ...
render() {
{/* ... */}
{this.state.showTimer && (
<div className="timerDiv">
<Timer
handleTimerClick={this.clickStart}
timeOut={this.timerZero}
/>
</div>
{/* ... */
)}
Timer.js
// ...
/*
I added `shouldComponentUpdate` lifecycle
with this, we stop the `Timer` component for rendering
and call `stopTimer` (instead of doing it inside the render method)
*/
shouldComponentUpdate() {
console.log(this.state.timer);
if (this.state.timer <= 0) {
this.stopTimer();
return false;
}
return true;
};
/*
Also added the a componentWillUnmount method for good practice
here if the component is unmounted the timer won't be running forever.
*/
componentWillUnmount() {
clearInterval(this.timer);
};
render() {
return (
<div className="Timer">
<div>{this.state.timer} seconds</div>
<button onClick={this.startTimer}>Start!</button>
{/* delete the call to `this.stopTimer` */}
</div>
);
}
Also as an extra, I recommend you to ignore the node_modules folder in a .gitignore file to make your projects leaner. all your project dependencies are listed in yarn.lock or package-lock.json so when I download your repo I get to download the same dependencies you are using.
cheers!!!

How to update state only for visual effect in React?

After click on delete button i want to make the selectedPost to null so that user gets a prompt to select post again. I am updating the state onDeleteClick(). But everytime i am updating, componentDidMount is getting called and update the data of selectedPost.
Is there any other way to make the state to null so that user get the specific prompt?
class FullPost extends Component {
state = {
selectedPost: null,
postVisible: false
}
componentDidUpdate() {
if (this.props.id) {
if (!this.state.selectedPost || (this.state.selectedPost && this.state.selectedPost.id !== this.props.id)) {
axios.get('https://jsonplaceholder.typicode.com/posts/' + this.props.id)
.then(response => {
this.setState({ selectedPost: response.data })
}
);
}
}
}
onDeleteClick = () => {
this.props.deletePost(this.state.selectedPost.id);
this.setState({ selectedPost: null });
console.log(this.state.selectedPost);
}
render() {
let post = <p style={{ textAlign: 'center' }}>Please select a Post!</p>;
if (this.state.selectedPost) {
post = (
<div className="FullPost">
<h1>{this.state.selectedPost.title}</h1>
<p>Content</p>
<div className="Edit">
<button className="Delete"
onClick={this.onDeleteClick}>
Delete</button>
</div>
</div>
);
}
return post;
}
}

Click handler for each button incorrectly returns the last button of a set

I am trying to add a click handler to each button that is generated in a loop and inserted into an array.
However, clicking a button always outputs the last button of each row of buttons and not the specific button itself.
My code is rather verbose, but we only need to be looking at the time.push() part and the click handler setup. Everything else is just setup.
import React from 'react';
import { friendlyTimeSlot, scopedTimeslots } from '../../utilities/helpers';
class TimeSlotStack extends React.Component {
constructor() {
super();
this.clickHandler = this.clickHandler.bind(this);
this.state = {
times: undefined
};
}
componentWillMount() {
this.updatePropsAndState(this.props);
}
componentWillReceiveProps(nextProps) {
this.updatePropsAndState(nextProps);
this.forceUpdate();
}
updatePropsAndState(props) {
const time = [];
let matchedTimeSlots;
if (props.promotionId) {
matchedTimeSlots = props.timeSlots.filter(timeSlot => {
const timeSlotsIds = timeSlot.AvailablePromotions.map(p => p.Id);
if (timeSlotsIds.includes(props.promotionId)) {
return timeSlot;
}
return false;
});
} else {
matchedTimeSlots = props.timeSlots.filter(timeSlot => timeSlot.HasStandardAvailability);
}
const scopedTimes = scopedTimeslots(matchedTimeSlots, props.preferredTimeSlot);
scopedTimes.forEach((item, i) => {
const friendlyTime = friendlyTimeSlot(item.TimeSlot, true);
const leaveTimeRequired = item.IsLeaveTimeRequired;
let itemPromo;
let leaveTime;
let itemPrice;
if (props.promotionId) {
itemPromo = item.AvailablePromotions.find(ourItem => ourItem.Id === props.promotionId);
leaveTime = itemPromo.LeaveTime || item.LeaveTime;
itemPrice = (itemPromo.BasePrice > 0) ? `£${itemPromo.BasePrice}` : '';
} else {
leaveTime = item.LeaveTime;
}
time.push(
<button
className="btn btn-default"
type="button"
onClick={(e) => this.clickHandler(e)}
ref={input => {
this.button = input;
}}
key={i}
data-time={friendlyTime}
data-leave-time-required={leaveTimeRequired}
data-leave-time={leaveTime.slice(0, -3)}
data-promotion-id={props.promotionId}
>
{friendlyTimeSlot(item.TimeSlot)}<br />{itemPrice}
</button>
);
});
this.setState({
times: time
});
}
clickHandler(e) {
e.preventDefault();
console.log(this.button.dataset);
}
render() {
if (this.state.times && this.props.name && this.props.description) {
return (
<div className="panel panel-default">
<div className="panel-heading">
<h3 className="panel-title">{this.props.name}</h3>
</div>
<div className="panel-body">
<p>{this.props.description}</p>
{this.state.times}
</div>
</div>
);
}
return (
<p>No times available.</p>
);
}
}
TimeSlotStack.propTypes = {
name: React.PropTypes.string.isRequired,
description: React.PropTypes.string.isRequired,
timeSlots: React.PropTypes.array.isRequired,
preferredTimeSlot: React.PropTypes.string.isRequired,
promotionId: React.PropTypes.number
};
export default TimeSlotStack;
When I then click a button, I always get the last button from each list. Hopefully the screenshot below will help make this clearer:
The log above comes from:
clickHandler(e) {
e.preventDefault();
console.log(this.button.dataset);
}
...but was generated by clicking the first buttons of each row. You can see that it always outputs the last only.
Is there something I'm doing wrong? This is my first React project and it's gotten me all flustered. Please let me know if I'm doing something that's not the React way that could be causing this.
Thanks!
You are overwriting the button variable, this in this context is a reference to a TimeSlotStack instance. To do what you want you need to maintain a list of buttons, for instance.
constructor() {
super();
this.clickHandler = this.clickHandler.bind(this);
this.buttons = [];
this.state = {
times: undefined
};
}
....
// using a IFE so `clickHandler` is called with the correct index
((idx) => {
time.push(
<button
className="btn btn-default"
type="button"
onClick={(e) => this.clickHandler(e, idx)}
ref={button => {
this.buttons.push(button);
}}
key={idx}
data-time={friendlyTime}
data-leave-time-required={leaveTimeRequired}
data-leave-time={leaveTime.slice(0, -3)}
data-promotion-id={props.promotionId}
>
{friendlyTimeSlot(item.TimeSlot)}<br />{itemPrice}
</button>
);
})(i);
....
clickHandler(e, i) {
e.preventDefault();
console.log(this.buttons[i].dataset);
}

Disable react-router Link in react

I'm new to React and got a issue to disable a link covert by a button element.
I tried the following:
class ShoppingCartLink extends React.Component {
constructor(){
super();
ShoppingCartStore.register(this.refresh.bind(this));
this.state = {count:0};
this.item = "items";
this.linkDisabled = new Boolean(true);
}
refresh(){
if (ShoppingCartStore.items.length === 0 || ShoppingCartStore.items.length > 1 )
{
this.item = "items";
}
else
{
this.item = "item";
}
if (ShoppingCartStore.items.length !== 0)
{
this.linkDisabled = false;
}
this.setState({count: ShoppingCartStore.items.length});
}
render() {
return (
<div>
<button type="button" disabled = {this.linkDisabled}>
<Link to="shoppingCart">Shopping Cart: {this.state.count} {this.item}</Link>
</button>
</div>
)
}
}
By default the Link should be disbaled as long no item is added to the cart.
I debugged through it and when the constructor is called "linkDisabled" is set to true as well in render(). The problem is that the link is still enabled.
Thanks for your help!
There is no "disabled" attribute for anchor tags, and Links are just router aware anchor tags. You can use one of the two things
1. Diasble pointer events with css
REACT Component
constructor(){
super();
ShoppingCartStore.register(this.refresh.bind(this));
this.state = {
count:0,
linkDisabled: 'disable-link';
};
}
refresh(){
const length = ShoppingCartStore.items.length;
const classValue = (length === 0)? 'disable-link': '';
this.setState({
count: length,
linkDisabled: classValue
});
}
render() {
const length = ShoppingCartStore.items.length;
return (<div>
<button type="button" disabled={this.state.linkDisabled}>
<Link to="shoppingCart" className={this.state.linkDisabled}>Shopping Cart: {this.state.count} {((length > 0)?"items":"item")}</Link>
</button>
</div>);
}
CSS
. disable-link {
pointer-events: none;
}
2. Make use of event.preventDefault() on click of link if there are no items in the cart
constructor(){
super();
ShoppingCartStore.register(this.refresh.bind(this));
this.state = {
count:0,
linkDisabled: true
};
}
refresh(){
const length = ShoppingCartStore.items.length;
this.setState({
count: length,
linkDisabled: (length !== 0)
});
}
handleClick = (e) => {
if(this.state.linkDisabled == true) {
e.preventDefault();
}
}
render() {
const length = ShoppingCartStore.items.length;
return (<div>
<button type="button" disabled={this.state.linkDisabled}>
<Link to="shoppingCart" onClick={this.handleClick}>Shopping Cart: {this.state.count} {((length > 0)?"items":"item")}</Link>
</button>
</div>);
}
However in both these cases you can access the route with commandline as only pointer events are disabled.
linkDisabled does not need to be in state. This opens up possibilities of changing state and forgetting to update linkDisabled. It is better to compute it in render.
class ShoppingCartLink extends React.Component {
constructor(){
super();
ShoppingCartStore.register(this.refresh.bind(this));
this.state = {count: 0};
}
refresh() {
this.setState({count: ShoppingCartStore.items.length});
}
render() {
const linkDisabled = this.state.count === 0;
const item = this.state.count === 1 ? "item" : "items";
return (
<div>
<button type="button" disabled={linkDisabled}>
<Link to="shoppingCart">Shopping Cart: {this.state.count} {item}</Link>
</button>
</div>
)
}
}
This way, if you ever add more to the component and have to setState in a different place, you will not need to worry about duplicating the logic for linkDisabled and item.
constructor(){
super();
ShoppingCartStore.register(this.refresh.bind(this));
this.state = {
count:0,
linkDisabled: true
};
}
handleClick(event) {
if(this.state.linkDisabled) event.preventDefault();
}
refresh(){
const length = ShoppingCartStore.items.length;
this.setState({
count: length,
linkDisabled: (length === 0)
});
}
render() {
const length = ShoppingCartStore.items.length;
return (<div>
<Link to="shoppingCart"
onClick={this.handleClick.bind(this)}>Shopping Cart: {this.state.count} {((length > 0)?"items":"item")}</Link>
</div>);
}
After some refactoring ... Try this ?

Categories

Resources