Re-render the component with new data without having local state in React - javascript

I'm practicing react and redux and I'm creating a simple app where I have a sidebar showing a list of categories that is visible on every route and the main area that initially displays all the books I have and when clicking on a category link on the sidebar the main area loading another component with all the books related to this category.
Here's my routes setup in the App.js file ...
class App extends Component {
async componentDidMount() {
try {
await this.props.asyncLoadBooks();
await this.props.asyncLoadCategories();
} catch (error) {
console.log(error);
}
}
render() {
return (
<>
<Header />
<div className="global-wrapper">
<div className="container">
<aside className="side-bar">
<Categories />
</aside>
<main className="main-content">
<Switch>
<Route exact path="/" component={Books} />
<Route
exact
path="/category/:id"
component={Category}
/>
<Route component={NotFound} />
</Switch>
</main>
</div>
</div>
</>
);
}
}
In the App.js as you can see I'm loading the data via a local JSON file with axios in the Actions files of the booksActions and categoriesAction, it's pretty straightforward.
And here's the Categories component ...
class Categories extends Component {
render() {
const { categories } = this.props;
let categoriesList;
if (categories && categories.length !== 0) {
categoriesList = categories.map(category => (
<li key={category.id}>
<Link to={`/category/${category.id}`}>{category.name}</Link>
</li>
));
} else {
categoriesList = <Loading />;
}
return (
<div>
<h2>Categories</h2>
<ul>{categoriesList}</ul>
</div>
);
}
}
const mapState = state => ({
categories: state.categories.categories
});
export default connect(mapState)(Categories);
And I'm firing another action in the ComponentDidMount() of the single Category component to get all the books related to that component and render them ...
class Category extends Component {
componentDidMount() {
this.props.getCategoryBooks(this.props.match.params.id);
}
componentDidUpdate(prevProps) {
if (prevProps.match.params.id !== this.props.match.params.id) {
this.props.getCategoryBooks(this.props.match.params.id);
}
}
render() {
const { categoryBooks } = this.props;
return (
<div>
{/* <h1>{this.props.match.params.id}</h1> */}
{categoryBooks &&
categoryBooks.map(book => {
return <div key={book.id}>{book.title}</div>;
})}
</div>
);
}
}
const mapState = state => ({
categories: state.categories.categories,
categoryBooks: state.books.categoryBooks
});
const mapActions = {
getCategoryBooks
};
export default connect(
mapState,
mapActions
)(Category);
Now, everything is working the first time, however, when I click on another category the <Category /> component doesn't get updated because I'm dispatching the action in the componentDidMount() thus the component already mounted the first time, so it doesn't dispatch the action again after I click on another category, now what is the best way to handle this?
The second issue is where I'm on a category route http://localhost:3000/category/9967c77a-1da5-4d69-b6a9-014ca20abd61 and I try to refresh the page, the categoris list loads fine on the sidebar, but the single component shows empty, and when I look on the redux-devtools I find that the GET_CATEGORY_BOOKS action gets fired before the LOAD_BOOKS and LOAD_CATEGORIES in the App.js file, because the child componentDidMount() method gets called before its parent equivalent method. How to solve this as well?
I hope you guys can help me in this.
Edit
As ##NguyễnThanhTú noticed, the componentDidupate had a typo, now it works when clicking on another category.
That leaves us with the second issue when reloading the page in the category route and the data doesn't show because of the App.js componentDidMount fires after its children components.
Edit
Here's a repo on Github for this project ...
https://github.com/Shaker-Hamdi/books-app

In your booksActions.js, add this:
export const getCategoryBooksV2 = categoryId => {
return async (dispatch, getState) => {
const { books } = getState();
if (books.books.length === 0) {
console.log('Only executing once') // testing purpose only
const response = await axios.get("books.json");
const data = response.data.books;
dispatch(loadBooks(data));
dispatch(getCategoryBooks(categoryId));
}
dispatch(getCategoryBooks(categoryId));
};
};
In your Category.js, use that new action creator:
import { getCategoryBooksV2 } from "../books/booksActions";
...
componentDidMount() {
this.props.getCategoryBooksV2(this.props.match.params.id);
}
...
const mapActions = {
getCategoryBooksV2
};
This solution is inspired by this example:
function incrementIfOdd() {
return (dispatch, getState) => {
const { counter } = getState();
if (counter % 2 === 0) {
return;
}
dispatch(increment());
};
}
From the Redux-Thunk Documentation
This is the demo:

Related

React native wrapper component re-renders on each page navigation

I am developing an android app using react-native and i have a but of a struggle of figuring out why my component re-renders on each page navigation.
In my case i have created a wrapper component called Container.android.js
const Container = props => {
useEffect(() => {
// fetching some data from async storage
},[])
// Using my hook here
const {code, error} = usePdaScan({
onEvent: (code) => {
// setting state via useState
},
onError: (error) => {
Alert.alert('Error', error);
},
trigger: 'always'
});
return <View>
{props.children}
</View>
}
Then i declare routes with Stack.Screen where each stack uses a component wrapped with the Container component.
<Stack.Screen name="Overview" component={Overview} />
And my Overview compnent is this
const Overview = props => {
return <Container>
<Text>Overview page</Text>
</Container>
}
My problem is that inside the Container component, there is a hook called usePdaScan. Each time i navigate to another page and the hook gets called, the Container component re-renders twice... I cant get a lead on this... Halp!
UPDATE: My homepage is a class component where it seems to work ok (render only once)
class Home extends Component {
state = {
productBarcodes: null
}
componentDidMount(){
// get data fetches data from async storage
getData('#productBarcodes').then(res => {
this.setState({
...this.state,
productBarcodes: JSON.parse(res)
})
})
}
render() {
const { productBarcodes } = this.state;
return (
<Container {...this.props}>
<View style={{marginBottom: 20, flex:1}}>
{productBarcodes.length} Products
</View>
</Container>
)
}
}
The usePdaScan hook in the Container component gets called once on my Homepage but twice on every other page like Overview etc... Both Homepage and Overview are wrapped with my Container component

Maintain the context data for each child component on React router change

I am beginner in React and working on React app where I am using the context to maintain the button state which can be in any one phase out of start, loading, stop.
I am passing the context to app component and have a React router to render the component on basis of route. I am rendering card component by looping through data where each card have one Button Component.
On button click of card1 the button1 should get in loading phase for 10-15 seconds depending on api response time. Once response comes it should be in stop phase. Similarly for button2 and button3 if clicked together. Now that seems to be working fine when I click on button1 and button2 instantly.
But when I click on 2 buttons together and move to another route and quickly come back I don't see my buttons to be in loading state though the api response is still pending. I should be seeing them in loading state and when response comes I should see them in start or stop phase.
I know I can use local or session storage but I don't want to due to some code restrictions.
Here is the stack blitz link : https://stackblitz.com/edit/node-3t59mt?file=src/App.js
Github Link: https://github.com/mehulk05/react-context-api
Button.jsx
import React, { useContext,useEffect, useState } from 'react'
import DbContext from '../Context/sharedContext'
function Button(props) {
console.log(props)
const {
requestStartDbObj,
setRequestStartDbObj
} = useContext(DbContext)
const [state, setstate] = useState(props.text?.status ?? "start")
useEffect(() => {
setstate(props.text?.status??"start")
return () => {
}
}, [state])
console.log(requestStartDbObj)
const start = ()=>{
setRequestStartDbObj({id:props.status.id, status:"loading"})
setstate("loading")
setTimeout(()=>{
setstate("stop")
setRequestStartDbObj({id:props.status.id, status:"stop"})
},5000)
}
return (
<div>
<button onClick={start}>{state}1</button>
</div>
)
}
export default Button
Card.jsx
function Card(props) {
const {
requestStartDbObj,
} = useContext(DbContext)
return (
<div>
<h1>{props.data.name}</h1>
<Button status={props.data} text={requestStartDbObj} />
</div>
)
}
Component1.jsx
function Component1() {
let data = [
{
id: 1,
name: "card1",
status: "start",
},
{
id: 2,
name: "card2",
status: "start",
},
{
id: 3,
name: "card3",
status: "start",
},
];
return (
<div>
<h1>Hello</h1>
{data.map((d, i) => (
<Card key={i} data={d} />
))}
</div>
);
}
ComponentWrapper.jsx
<h3>Wrpper</h3>
<Routes>
<Route path="/" element={<Component1 />} />
<Route path="about" element={<Component2 />} />
</Routes>
</div>
App.js
function App() {
return (
<div className="App">
<BrowserRouter>
<Link to="/">Home</Link> <br></br>
<Link to="/about">Comp 2</Link>
<DbProvider>
<ComponentWrapper/>
</DbProvider>
</BrowserRouter>
</div>
);
}
The issue is that your DbProvider context isn't the source of truth as to the status, it's not the component maintaining the requestStartDbObj state. Each Button is duplicating the state locally and using its own start function. Each Button is also replacing the requestStartDbObj state of the context, so when switching back to the home path all the buttons get the same initial state value. Upon navigating away from the home path the Button component is unmounted, so the state updates on timeout are lost.
You should move the start logic to the sharedContext so DbProvider maintains control over the state updates. start should consume an id argument so it can correctly update the status for that specific object.
DbProvider
const DbProvider = (props) => {
const [requestStartDbObj, setRequestStartDbObj] = useState({});
const { children } = props;
const start = (id) => {
setRequestStartDbObj((state) => ({
...state,
[id]: { status: "loading" }
}));
setTimeout(() => {
setRequestStartDbObj((state) => ({
...state,
[id]: { status: "stop" }
}));
}, 5000);
};
return (
<DbContext.Provider
value={{
requestStartDbObj,
start
}}
>
{children}
</DbContext.Provider>
);
};
Card
Only pass the id prop through to Button from data prop that was passed from Component1 when mapped.
function Card({ data }) {
return (
<div>
<h1>{data.name}</h1>
<Button id={data.id} />
</div>
);
}
Button
Use the id prop to pass to start function provided by the context. Also use the id to access the current status.
function Button({ id }) {
const { requestStartDbObj, start } = useContext(DbContext);
return (
<div>
<button onClick={() => start(id)}>
{requestStartDbObj[id]?.status || "start"}-{id}
</button>
</div>
);
}

React: Persisting State Using Local Storage

I am coding an app in which there is a collection of reviews and a person can respond to a review, but each review can only have one response. So far, I am doing this by rendering a ReviewResponseBox component in my ReviewCardDetails component and passing the review_id as props.
I have implemented the logic so that once there is one ReviewResponse, the form to write another will no longer appear. However, before I was initializing the state in this component with an empty array, so when I refreshed my page the response went away and the form came back up. (This is now commented out)
I am trying to resolve this by persisting my state using React LocalStorage but am having trouble writing my method to do this. Here is what I have so far:
Component that renders ReviewResponseBox and passes review_id as props:
import React from "react";
import './Review.css';
import { useLocation } from "react-router-dom";
import StarRatings from "react-star-ratings";
import ReviewResponseBox from "../ReviewResponse/ReviewResponseBox";
const ReviewCardDetails = () => {
const location = useLocation();
const { review } = location?.state; // ? - optional chaining
console.log("history location details: ", location);
return (
<div key={review.id} className="card-deck">
<div className="card">
<div>
<div className='card-container'>
<h4 className="card-title">{review.place}</h4>
<StarRatings
rating={review.rating}
starRatedColor="gold"
starDimension="20px"
/>
<div className="card-body">{review.content}</div>
<div className="card-footer">
{review.author} - {review.published_at}
</div>
</div>
</div>
</div>
<br></br>
<ReviewResponseBox review_id={review.id}/>
</div>
);
};
export default ReviewCardDetails;
component that I want to keep track of the state so that it can render the form or response:
import React from 'react';
import ReviewResponse from './ReviewResponse';
import ReviewResponseForm from './ReviewResponseForm';
import { reactLocalStorage } from "reactjs-localstorage";
class ReviewResponseBox extends React.Component {
// constructor() {
// super()
// this.state = {
// reviewResponses: []
// };
// }
fetchResponses = () => {
let reviewResponses = [];
localStorage.setResponses
reviewResponses.push(reviewResponse);
}
render () {
const reviewResponses = this.getResponses();
const reviewResponseNodes = <div className="reviewResponse-list">{reviewResponses}</div>;
return(
<div className="reviewResponse-box">
{reviewResponses.length
? (
<>
{reviewResponseNodes}
</>
)
: (
<ReviewResponseForm addResponse={this.addResponse.bind(this)}/>
)}
</div>
);
}
addResponse(review_id, author, body) {
const reviewResponse = {
review_id,
author,
body
};
this.setState({ reviewResponses: this.state.reviewResponses.concat([reviewResponse]) }); // *new array references help React stay fast, so concat works better than push here.
}
getResponses() {
return this.state.reviewResponses.map((reviewResponse) => {
return (
<ReviewResponse
author={reviewResponse.author}
body={reviewResponse.body}
review_id={this.state.review_id} />
);
});
}
}
export default ReviewResponseBox;
Any guidance would be appreciated
You would persist the responses to localStorage when they are updated in state using the componentDidUpdate lifecycle method. Use the componentDidMount lifecycle method to read in the localStorage value and set the local component state, or since reading from localStorage is synchronous directly set the initial state.
I don't think you need a separate package to handle this either, you can use the localStorage API easily.
import React from "react";
import ReviewResponse from "./ReviewResponse";
import ReviewResponseForm from "./ReviewResponseForm";
class ReviewResponseBox extends React.Component {
state = {
reviewResponses: JSON.parse(localStorage.getItem(`reviewResponses-${this.props.review_id}`)) || []
};
storageKey = () => `reviewResponses-${this.props.review_id}`;
componentDidUpdate(prevProps, prevState) {
if (prevState.reviewResponses !== this.state.reviewResponses) {
localStorage.setItem(
`reviewResponses-${this.props.review_id}`,
JSON.stringify(this.state.reviewResponses)
);
}
}
render() {
const reviewResponses = this.getResponses();
const reviewResponseNodes = (
<div className="reviewResponse-list">{reviewResponses}</div>
);
return (
<div className="reviewResponse-box">
{reviewResponses.length ? (
<>{reviewResponseNodes}</>
) : (
<ReviewResponseForm addResponse={this.addResponse.bind(this)} />
)}
</div>
);
}
addResponse(review_id, author, body) {
const reviewResponse = {
review_id,
author,
body
};
this.setState({
reviewResponses: this.state.reviewResponses.concat([reviewResponse])
}); // *new array references help React stay fast, so concat works better than push here.
}
getResponses() {
return this.state.reviewResponses.map((reviewResponse) => {
return (
<ReviewResponse
author={reviewResponse.author}
body={reviewResponse.body}
review_id={this.state.review_id}
/>
);
});
}
}

React - Add user to list of Favorites

I have a simple user list with several details from the following api: https://gorest.co.in/public-api/users, where I want to add a selected user to a list of favorites. I am working with react-router to navigate between pages. Is this possible with React or do I also need Redux?
I have a complete LIVE EXAMPLE here with the user page and favorites.
Here is the code below for the user list:
import React from "react";
import axios from "axios";
import NavLinks from "./components/navLink";
export default class UserList extends React.Component {
constructor(props) {
super(props);
this.state = {
list: [],
addToFav: false
};
this.list = [];
}
componentDidMount() {
this.getList();
}
/* get users list */
getList = async () => {
const api =
"https://gorest.co.in/public-api/users?_format=json&access-token=3qIi1MDfD-GXqOSwEHHLH73Y3UitdaFKyVm_";
await axios
.get(api)
.then(response => {
this.list = response.data.result;
this.setState({
list: this.list
});
})
.catch(err => {
console.log(err);
});
};
addToFav = () => {
this.setState(
{
addToFav: !this.state.addToFav
},
() => console.log(this.state.addToFav)
);
};
render() {
let style = {
display: "grid",
gridTemplateColumns: "repeat(auto-fill, minmax(250px, 1fr))",
padding: "1rem",
gridGap: "1rem 1rem"
};
return (
<div>
<NavLinks />
<ul style={style}>
{this.state.list.map(user => {
return (
<li key={user.id}>
<div>
<img className="thumb" alt="" src={user._links.avatar.href} />
</div>
<div className="userInfo">
<p>
{user.first_name} {user.last_name}
</p>
</div>
<button onClick={this.addToFav}>Add to Favorites</button>
</li>
);
})}
</ul>
</div>
);
}
}
Thank you!
Here's a working codesandbox: https://codesandbox.io/s/brave-fire-4kd4p
This train of thought pretty much follows what #Chris G mentioned. Have a top-level state that holds the list of users and the favorites list. Then pass those as props to the individual components.
App.js
Hit your API here instead of inside your UserList component to prevent any unnecessary re-renders.
import React, { Component } from "react";
import UserList from "./userList";
import FavoriteList from "./favoriteList";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import axios from "axios";
export default class App extends Component {
state = {
list: [],
favorites: []
};
addFavorite = favorite => {
const { favorites } = this.state;
if (!favorites.some(alreadyFavorite => alreadyFavorite.id == favorite.id)) {
this.setState({
favorites: [...this.state.favorites, favorite]
});
}
};
getList = async () => {
const api =
"https://gorest.co.in/public-api/users?_format=json&access-token=3qIi1MDfD-GXqOSwEHHLH73Y3UitdaFKyVm_";
await axios
.get(api)
.then(response => {
this.setState({
list: response.data.result
});
})
.catch(err => {
console.log(err);
});
};
componentDidMount() {
this.getList();
}
render() {
return (
<Router>
<Switch>
<Route
path="/"
exact
render={() => (
<UserList list={this.state.list} addFavorite={this.addFavorite} />
)}
/>
<Route
path="/favorites"
render={() => <FavoriteList favorites={this.state.favorites} />}
/>
</Switch>
</Router>
);
}
}
UserList.js
Call the addFavorite event-handler on button-click to pass that item back up to the parent-state.
import React from "react";
import NavLinks from "./components/navLink";
export default class UserList extends React.Component {
render() {
let style = {
display: "grid",
gridTemplateColumns: "repeat(auto-fill, minmax(250px, 1fr))",
padding: "1rem",
gridGap: "1rem 1rem"
};
return (
<div>
<NavLinks />
<ul style={style}>
{this.props.list.map(user => {
return (
<li key={user.id}>
<div>
<img className="thumb" alt="" src={user._links.avatar.href} />
</div>
<div className="userInfo">
<p>
{user.first_name} {user.last_name}
</p>
</div>
<button onClick={() => this.props.addFavorite(user)}>
Add to Favorites
</button>
</li>
);
})}
</ul>
</div>
);
}
}
Favorite.js
Use the favorites array that was passed in as a prop and iterate over it.
import React from "react";
import NavLinks from "./components/navLink";
export default class FavoriteList extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
const { favorites } = this.props;
return (
<div>
<NavLinks />
<ul>
{favorites.map(user => {
return (
<li key={user.id}>
<div>
<img className="thumb" alt="" src={user._links.avatar.href} />
</div>
<div className="userInfo">
<p>
{user.first_name} {user.last_name}
</p>
</div>
</li>
);
})}
</ul>
</div>
);
}
}
Is this possible with React or do I also need Redux?
Most if not all of those problems can be solved without redux just by using component state. It just gets increasingly difficult to pass the state to the components needing it the more global state you have and the more components at different depth need to access and update it.
In your case it might be sufficient to store the favorites in a component state high up the tree and pass it to the components consuming it. You could either pass it directly to the components or you could use react context to make it accessible to components deep in the tree.
A simple example:
const FavoritesContext = React.createContext({favorites: []});
const FavoritesProvider = ({children}) => {
const [favorites, setFavorites] = useState([]);
const add = useCallback(favorite => setFavorites(current => [...current, favorite]), [setFavorites]);
return (
<FavoritesContext.Provider value={{favorites, add}}>
{children}
</FavoritesContext.Provider>
};
You can use it like that:
<FavoritesProvider>
<MyApp />
</FavoritesProvider>
then anywhere in a component in your app:
const MyComponent = () => {
const {favorites, add} = useContext(FavoritesContext);
const [draft, setDraft] = useState('');
const handleChange = event => setDraft(event.target.value);
const handleAdd = () => {
add(draft);
setDraft('');
};
return (
<div>
<ul>
{favorites.map(favorite => <li>{favorite}</li>)}
</ul>
<input value={draft} type="text" onChange={handleChange} />
<button onClick={handleAdd}>Add</button>
</div>
);
}
In this simple example the favorites are just text but they could as well be objects. Also it demonstrates how you could provide a handler for adding a favorite. You could implement e.g. a handler for removing favorites in the same way.
Persisting your favorites is yet another topic you may need to deal with. You could use e.g. localStorage for that or you could store that in a database on a server and fetch it when your app mounts the first time.
I have changed your file a bit take a look - https://codesandbox.io/s/clever-butterfly-vb2iz
One way is to use the localstorage of browser.
But this way is slighty expensive and synchronous.
Update the list whenever the favorited item status is changed via
localStorage.setItem('users',JSON.stringify(users));
And look for the favorited items via
localStorage.getItem('users');//You need to parse this by JSON.parse()
Maintain a isFavorite variable in the object list.
let users=[{name:"Mr.A",isFavorite:false},{name:"Mr.B",isFavorite:true},...];
On the click of favoriting button this.addToFav change it as follows
addToFav=user=>{
const {users}=this.state;
this.setState({
users:users.map(userObject=>userObject.id===user.id?
{...userObject,isFavorite:!userObject.isFavorite}:user)
},()=>{saveToLocal(this.state.users)});
}
Now you can access the favorite items even if the page is reloaded and stays there till you clear the storage.Use this localStorage.clear() for that.
First I would change your onClick to this:
<button onClick={() => this.addToFav(user.id)}>Add to Favorites</button>
This will allow you to pass the id to the addToFave function.
Then I would add a new state called faves (an array) and every time someone clicks the add button I would add their id into this array. This will allow you to filter your original list when you want to display the faves.
this.state = {
list: [],
faves: [],
};
}
addToFav = (id) => {
this.setState(prevState => ({
faves: [...prevState.faves, id],
}));
};
When I want to use the list of faves instead of the normal list I would do this:
const favesList = [];
this.state.list.map(listItem =>
this.state.faves.find(
faveId => listItem.id === faveId
) && favesList.push(item);
Then I would pass that to the faves component
I changed accordingly, please try
https://codesandbox.io/s/youthful-poincare-7oeh0
the key is you can use push state to your link like below
<Link to={{ pathname: "/favorites", state: { favList: this.props.favList }}} onClick={() => this.forceUpdate()}>
later on under your fav page call to retrieve the state
this.props.location.state.favList
i have changed the code a little by using react context.
I would not use redux for this cause i think it would be a overkill.
Anyways here is the updated sandbox...
Link for sandbox

Button click won't update state in my React app

A button click shall filter my job-card array to only one category. E.g. button "Marketing" should filter to those jobs from array who have prop "jobstags: Marketing". I used a very similar procedure like for my input which filters jobs perfectly.
I can console log my event (the button click) with the according value ("Marketing"). But it still doesn't filter correctly...
In my app I did this:
export default class App extends Component {
state = {
jobs: jobs,
searchfield: '',
jobtags: ''
}
onSearchChange = event => {
this.setState({ searchfield: event.target.value })
}
onClickChange = event => {
console.log(event.target.value)
this.setState({ jobtags: event.target.value })
}
render() {
const filteredJobs = this.state.jobs.filter(job => {
return (
job.position
.toLowerCase()
.includes(this.state.searchfield.toLowerCase()) ||
job.company
.toLowerCase()
.includes(this.state.searchfield.toLowerCase()) ||
job.jobtags.toLowerCase().includes(this.state.jobtags.toLowerCase())
)
})
// this.save()
if (this.state.jobs.length === 0) {
return <Loading>Loading...</Loading>
} else {
return (
<Router>
<React.Fragment>
<Route
exact
path="/"
render={() => (
<Home
jobs={filteredJobs}
searchChange={this.onSearchChange}
clickChange={this.onClickChange}
/>
)}
/>
onClickChange is what should update the state of tags
In my Home component I then simply pass the value on to the Categories component:
<Categories clickChange={clickChange} />
Finally it arrives in my Categories component where I say:
export default class Categories extends Component {
render() {
const { clickChange } = this.props
return (
<Wrapper>
<button value="Marketing" onClick={clickChange}>
<img
alt="Button"
src={require('/Users/markus/Documents/q4-2018/jobs-app/src/img/computer.png')}
/>
Frontend
</button> ...
Any ideas? Thx!
maybe you have to bind the "this" of "onClickChange", for example in the constructor of your App class.
Example :
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
jobs: jobs,
searchfield: '',
jobtags: ''
};
this.onClickChange = this.onClickChange.bind(this);
and it will work I think
You will have to bind it. Add this line to your constructor:
this.onClickChange = this.onClickChange.bind(this);

Categories

Resources