componentDidMount not called, its not working at all it seems - javascript

I tried many things. Same code is working in my other project but not in the current one
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import getProductCategories from '../../redux/actions/productCategoryAction'
import "./ProductCategory.css"
export class ProductCategory extends Component {
static propTypes = {
productCategories: PropTypes.array.isRequired
}
componentDidMount() {
console.log('Mounted!');
this.props.getProductCategories();
}
render() {
return (
<div className="main-card-body">
<div className="main-card-container">
{this.props.productCategories.map((pc, i) => {
return (
<div key={i} className="main-card-card" >
<div className="main-card-face main-card-face1">
<div className="main-card-content">
<img src={pc.image} alt={pc.alt} />
</div>
</div>
<div className="main-card-face main-card-face2">
<div className="main-card-content">
<h3> {pc.title}</h3>
<p>{pc.description}</p>
</div>
</div>
</div>
)
})}
</div>
</div>
)
}
}
const mapStateToProps = state => ({
productCategories: state.productCategory.productCategories
})
const mapDispatchToProps = dispatch => {
return {
getProductCategories: () => {
dispatch(getProductCategories())
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(ProductCategory)
tried without mapDispatchToProps as:
export default connect(mapStateToProps, {getProductCategories})(ProductCategory)
componentDidMount failing without any error, not showing console.log string as well.
Although i crosschecked with each and every means i do have still can't resolve.
enter image description here
Found answer all thanks to Michalis Garganourakis and cubrr
In App.js i was importing this class based component "ProductCategory" with curly braces. importing it without curly braces did the job as i am exporting it as "export default"
Again thanks Michalis Garganourakis and cubrr
Cubrr answered this on the very first go. it took me lot of time to understand this silly thing :D :D

Based on the image you added, the error seems to occur on render function, so the componentDidMount never gets triggered for this exact reason.
Try checking if this.props.productCategories exists before trying to use .map() on it. This should allow render function to run succesfully, and this will then trigger the componentDidMount as per react's lifecycle method order
this.props.productCategories && this.props.productCategories.map((pc, i) ...
Also, try removing the export on your first row, keeping just the export default of your last row where you also make use of connect HOC, like:
class ProductCategory extends Component {
// ...
}
export default connect(mapStateToProps, mapDispatchToProps)(ProductCategory)

Related

Programatically redirect user to another page ReactJS [duplicate]

This question already has an answer here:
Problem in redirecting programmatically to a route in react router v6
(1 answer)
Closed last year.
I want to programatically redirect the user to a loading page while I await for a response from the server api. I'm trying to do this inside a class component
The code I've got looks more or less like this:
class App extends Component {
constructor(props){
super(props);
}
handleSubmit = () => {
useNavigate("/loading")
}
}
render() {
return (
<div>
<button onClick={this.handleSubmit}>
Upload!
</button>
</div>
);
}
}
export default App;
The thing is that nothing happens when i click the "Upload!" button. I've read that useNavigate cannot be used inside a class component but I'm not sure how I could implement this differently.
I guess my question is, how can I use useNavigate inside a class component?
EDIT:
Thanks for your responses. I finally decided to convert my code to a function using these steps: https://nimblewebdeveloper.com/blog/convert-react-class-to-function-component
It now works like a charm.
Your clarification is correct, useNavigate() is a hook and therefore can only be used in a functional component. I'm thinking as an alternative you can wrap your App with withRouter, a HOC that gives the wrapping component access to the match, location, and history objects. From there, you can update the location with history.push('/loading').
Please see here for more information on history.
You cannot use useNavigate which is a react hook inside of class component.
you can by the way use react-router-dom which provide different way to manipulate browser url.
Create a functional component as a Wrapper
import { useNavigate } from 'react-router-dom';
export const withRouter = (ClassComponent) => {
const RouterWrapper = (props) => {
const navigate = useNavigate();
return (
<ClassComponent
navigate={navigate}
{...props}
/>
);
};
return RouterWrapper;
};
Then in your App.js, export it by wraping with the functional component
import { withRouter } from './wrapper';
class App extends Component {
constructor(props){
super(props);
}
handleSubmit = () => {
useNavigate("/loading")
}
render() {
return (
<div>
<button onClick={this.handleSubmit}>
Upload!
</button>
</div>
);
}
}
export default withRouter(App);

Exporting default statement

I need to understand the export and import statement in React (Might involve the use of HOC)
So I have a higher component known as withclass.js like this
import React from 'react';
const withClass = (WrappedComponent, ClassName) => {
console.log(WrappedComponent)
console.log(ClassName)
return (props) => (
<div className={ClassName}>
<WrappedComponent />
</div>
)
}
export default withClass;
And inside our App.js, we do something like this
import withClass from '../hoc/withclass.js';
import classes from './App.css';
class App extends Component {
//some code here
//------ include render and return
export default withClass(App, classes.App);
Now, In Export statement I understand that he is passing two parameters which our withClass function requires as parameters but shouldn't he import something in withclass.js? How does our withclass.js receive those arguments?
Also, how does our return function (in withclass.js) get access to props here? (for example we passed props as an argument to our return function in withclass.js)?
I wasn't quite clear what you are asking for but regarding passing the argument you can do something like shown below. If I can get a little more explanation, I will update my answer.
import withClass from '../hoc/withclass.js';
class App extends Component {
//some code here
//------
return (
<Aux>
<button onClick={this.showPersonTrueHandler}>Show Persons </button>
<Ccockpit
coatiitle = {this.props.title}
cocPersonState = {this.state.showPerson}
cocperson = {this.state.person.length}
toggler = {this.togglerPersonHandler} />
{person}
</Aux>
)
}
}
export default withClass((parameter1, parameter2)=>{
//perform any action here...
})(App);

The prop `store.subscribe` is marked as required

I am trying to connect a component to the redux store, but am receiving:
Warning: Failed prop type: The prop 'store.subscribe' is marked as required inConnect(StoreLocation), but its value is 'undefined'.
I have been using redux with this project for awhile now without issue, but this component is erroring out for some reason and I'm clueless as to why at this point :(
The store populates a collection of stores (brick and mortar locations with addresses, phone numbers, etc used for shipping selections) within DeliverySection.js.
Then each StoreLocation.js component will allow the user to view it's info, select it, etc. It's bare bones right now as I am seeing the error even at this basic point. If I switch the export default connect()(StoreLocation) statement with export default StoreLocation it works without issue.
Any ideas?
DeliverySection.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
// Components
import Loader from '../../utils/Loader'
import StoreLocation from './StoreLocation'
// Stote
import { getAllStores } from '../../../store/actions/storeLocation'
import { REACT_APP_SITE_KEY } from '../../../shared/vars'
// CSS
import '../../../css/delivery.css'
class DeliverySection extends Component {
componentDidMount(){
this.props.getAllStores(REACT_APP_SITE_KEY);
}
render() {
const { stores, isLoading } = this.props
return (
<div>
<div className="delivery-heading">
<h2>Choose a store near you:</h2>
<button className="btn btn--red btn--heading" name="ship-to-address">Ship To An Address</button>
</div>
<div>
{isLoading ? (
<Loader />
) : (
!isLoading && !!stores ? (
stores.map((store, i) => <StoreLocation key={i} store={store} />)
) : (
<div>
There are no store locations to deliver to.<br />
Ship to an address!
</div>
)
)}
</div>
</div>
)
}
}
const mapStateToProps = (state) => {
return {
stores: state.storeLocation.stores,
isLoading: state.storeLocation.isLoading
}
}
export default connect(mapStateToProps, { getAllStores })(DeliverySection)
StoreLocation.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { setDelivery } from '../../../store/actions/checkout'
class StoreLocation extends Component {
render() {
const { store } = this.props
return (
<div className="store-location">
<div className="store-row">
<div className="store-col"><div className="store-title">{store.title}</div></div>
<div className="store-col">
{store.address}
{store.formatted_location &&
<div>{store.formatted_location}</div>
}
</div>
<div className="store-col">
<button className="btn select-store" onClick={() => this.props.setDelivery(store)}>Ship to this store<span className="icon-checkmark"></span></button>
</div>
</div>
<div className="store-row">
<div className="store-col">
<div className="ajax-message" data-hbs-id="postal-{id}"></div>
<input type="hidden" id={`postal-${store.id}`} value={store.postal} />
<div className="see-map"><span className="icon-location"></span>See on map</div>
</div>
<div className="store-col">{store.description}</div>
<div className="store-col"></div>
</div>
{store.phone &&
<div className="store-row">
<div className="store-col"></div>
<div className="store-col">{store.phone}</div>
<div className="store-col"></div>
</div>
}
</div>
)
}
}
export default connect(null, { setDelivery })(StoreLocation)
// export default StoreLocation
It's because you are using store as your prop name. You are overwriting the prop react-redux passes through the HOC. Since, the object you pass for store does not have a subscribe method, you get this error.
If you change the name of your prop, you'll be in good shape again.
After doing a quick Google I came across this post here.
That problem, which is similar to yours, was based on the way the store was exported. Have a look at that and see if gets you going in the right direction. I can't comment without seeing your store export code.
On a personal preference note I would use something other than 'store' as the variable for each instance in your map of stores. Since you are using Redux it could get semantically confusing whether you are referring to the Redux store or an instance of a store object.
I think it's fine that you are having StoreLocation handle the setting of delivery. I'm a big fan of breaking things down into smaller components.
Finally, just because I happen to notice it, you have a misspelling in DeliverySection. Line 8 reads //Stote. I'm guessing you meant //Store.
Apologies in advance as I think this should go under the comment section, but the code you pasted looks alright. You say disconnecting the StoreLocation component fixes things. Is there a reason you want to connect that component? You're not mapping any state to props or using dispatch in that component.
Otherwise, make sure that you're correctly initializing the store with the reducers you need and check that the modules you're using are imported properly - especially the ones you are passing to the connect function (getAllStores).

Expected onClick listener to be a function, instead got type object - react redux

As explained in the title, I am getting the error
Expected onClick listener to be a function, instead got type object
But I am unable to understand why this isnt working.
as far as I know, the onClick listener IS a function.
Here's, the CharacterList Component where the error comes from
import React,{Component} from 'react';
import {connect} from 'react-redux';
import {addCharacterById} from '../actions';
import {bindActionCreators} from 'redux';
class CharacterList extends Component{
render(){
//console.log('name : ',this.props.characters[2].name);
return(
<div>
<h3>Characters</h3>
<ul>
{this.props.characters.map((character)=>{
return(<li key={character.id}>{character.name}
<div
onClick={this.props.addCharacterById(character.id)}
>+</div>
</li>);
})}
</ul>
</div>
)
}
}
function mapStateToProps(state){
return {
characters:state
}
}
export default connect(mapStateToProps,{addCharacterById})(CharacterList);
And here's the action creator
export const ADD_CHARACTER='ADD_CHARACTER';
export function addCharacterById(id){
var action ={
type:ADD_CHARACTER,
id
}
return action;
}
So, what do you guys think?
what is the problem here?
The problem is that you're invoking the function immediately and then what's left is the return value, which might not be a function!
What you can do instead is wrap that function call inside an arrow function to solve your problem. It'll call the inner function once you onClick:
import React,{Component} from 'react';
import {connect} from 'react-redux';
import {addCharacterById} from '../actions';
import {bindActionCreators} from 'redux';
class CharacterList extends Component{
render(){
//console.log('name : ',this.props.characters[2].name);
return(
<div>
<h3>Characters</h3>
<ul>
{this.props.characters.map((character)=>{
return(<li key={character.id}>{character.name}
<div
onClick={() => this.props.addCharacterById(character.id)}
>+</div>
</li>);
})}
</ul>
</div>
)
}
}
function mapStateToProps(state){
return {
characters:state
}
}
export default connect(mapStateToProps,{addCharacterById})(CharacterList);
There's diferent ways of doing this, you could for example bind the parameter to the function, like:
{this.props.characters.map((character)=>{
return(<li key={character.id}>{character.name}
<div
onClick={this.props.addCharacterById.bind(null, character.id)}
>+</div>
</li>);
})}
Just shared as an example, so that you understand what's going on and why the first approach is more readable. You may want to look into why .bind in render is a bad practice by reading the article https://ryanfunduk.com/articles/never-bind-in-render/
onClick={this.props.addCharacterById(character.id)} this part of your code will execute immediately upon render() is call what you may want to do instead is:
onClick={(e)=> {this.props.addCharacterById(e, character.id)}}
Remember the first parameter pass to onClick is the click event.
Don't directly call functions in onClick event. It will recursively call the method. So make the onClick input as a callback method.
Change this line
onClick={this.props.addCharacterById(character.id)}
to
onClick={() => this.props.addCharacterById(character.id)}
There are some things that you need to change if you want to have good practices.
First, add mapDispatchToProps function.
import { bindActionCreators } from 'redux';
...
function mapDispatchToProps(dispatch) {
return {
addCharacterById: bindActionCreators(addCharacterById, dispatch)
};
}
Second, the event handler could be:
onClick={() => this.props.addCharacterById(character.id)}
Third, export your component:
export default connect(mapStateToProps, mapDispatchToProps)(CharacterList);
Just an additional answer, make sure that all the onClick on your code has this kind of format.
onClick={() => this.props.addCharacterById(character.id)}
Even if one onClick has a format like this onClick={this.props.addCharacterById(character.id)} it can be problematic

React/Redux simple access to Store from Component

I'm trying to figure out how to user the reducers with and inside my React-Component.
My goal is pretty easy - at least i thought so: I want to toggle a Drawer-Menu. I know I can solve this with React-Only, but I want to learn Redux.
So, I've got a Component…
import React, { Component } from 'react';
class Example extends Component {
// ???
render() {
return (
<button className="burgerbutton" onClick={this.toggleDrawer}</button>
<div className="drawerMenu isvisible" ></div>
);
}
}
export default Example;
also a Reducer
const initialState = {
buttonstate: false
};
const example = (state = initialState, action) => {
switch (action.type) {
case 'TOGGLE_BTN':
return Object.assign({}, state, {
buttonstate: !state.buttonstate
})
default:
return state
}
}
export default example
and an Action (although I don't know where to put that since it's so simple)
export const toggleDrawer = () => {
return {
type: 'TOGGLE_DRAWER'
}
}
I read a lot of tutorials and most of them want me to seperate between "Presentational Components" and "Container Components". I can't really see how these concepts apply here.
So what do I have to do to do to make this work? Am I looking at this problem from the right angle or do I need 12 "Container Components" to solve this?
I really hope this question makes sense at all and/or is not a duplicate!
In redux you have to dispatch action to update reducer state. So normally a component is connected to the redux store and communication is done through dispatch.
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { toggleDrawer } from 'action file location';
class Example extends Component {
toggleDrawerHandler() {
this.props.dispatch(toggleDrawer())
}
render() {
// access button state from this.props.buttonstate
return (
<button className="burgerbutton" onClick={this.toggleDrawerHandler.bind(this)}</button>
<div className="drawerMenu isvisible" ></div>
);
}
}
export default connect((store) => {buttonstate: store.buttonstate})(Example);
First, I'm really enjoying using redux "ducks" which is basically a redux reducer bundle. You put your reducer, action constants, and action creators in one file (called a duck). Then you may have multiple ducks for different modules or pieces of state that you'd then combine with combineReducers.
While #duwalanise has the right idea, I'd rather see the second param of connect() be used to directly map the action to dispatch (and there's a good shortcut for it) instead of having to use this.props.dispatch
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { toggleDrawer } from './duck';
class Example extends Component {
render() {
const { buttonstate, togglerDrawer } = this.props;
return (
<div>
<button className="burgerbutton" onClick={toggleDrawer}</button>
<div className="drawerMenu isvisible" ></div>
</div>
);
}
}
const mapStateToProps = (state) => ({
buttonstate: state.buttonstate,
});
export default connect(mapStateToProps, { toggleDrawer })(Example);
One side note, if you have a handler method in your component, it's better to do .bind(this) inside the constructor instead of using an arrow function or .bind(this) inside the event, ie don't do this onClick={() => /* do something */ } or this onClick={this.myHandler.bind(this)} This is an interesting (and long) read on it.
To touch on the Container vs Presentational Component piece: The idea would be to put all of your logic, handlers, redux actions etc into your containers, and pass that through props to your simple (hopefully stateless/pure function) presentational components. Technically, your component the way it's written could be turned into a stateless component:
const Example = ({ buttonstate, togglerDrawer }) => (
<div>
<button className="burgerbutton" onClick={toggleDrawer}</button>
<div className="drawerMenu isvisible" ></div>
</div>
);

Categories