Can't render the noofcartItems in my react UI. I get only NaN value as output in my UI.
Anything wrong in the syntax ? The context I created also seems to be failing.
Please ignore the console logs as I used it for debug purposes.
import CartContext from '../../CartStore/cart-context.js';
import CartIcon from '../Cart/CartIcon.js';
import './CartButton.css';
import { useContext } from 'react';
const CartButton = (props) => {
const context = useContext(CartContext);
const noofcartItems = context.items.reduce((curNo, item) => {
console.log(curNo, item.amount,curNo + item.amount, 'curNo + item.amount');
return curNo + item.amount;
}, 0);
console.log(noofcartItems,'No of cart items');
return (<button className='button' onClick={props.onClick}>
<span className='icon'>
<CartIcon/>
</span>
<span>Cart</span>
<span className='badge'>{noofcartItems}</span>
</button>
)
};
export default CartButton;
import React from 'react'
const CartContext = React.createContext({
items:[],
totalAmount: 0,
addItem: (item) => {},
removeItem: (id) => {}
});
export default CartContext;
You should console log your context.items array and check for the values of amount variable. It seems that one of the amount values must be undefined.
Related
I'm facing an error that has been searching by myself for 2 days. But currently It's still not resolved, so I came here to ask If anyone ever faced this?
I'm using Redux toolkit in a sharepoint online project for passing data to each other components.
The first component worked perfectly, but when I use useSelector function for the 2nd one, this error appears
Although when I tried using console.log for each component, both are still receiving the data but
using data for the 2nd component will happen this error.
So has anyone ever faced this please help me out~, here is my codes
slice:
import { createSlice } from '#reduxjs/toolkit';
export interface titleState {
title: string;
}
const initialState: titleState = {
title : 'Your title'
};
export const titleSlice = createSlice({
name: 'title',
initialState,
reducers: {
SET_TITLE: (state, action) => {
state.title = action.payload;
}
}
});
export const { SET_TITLE } = titleSlice.actions;
export default titleSlice.reducer;
store
import { configureStore } from '#reduxjs/toolkit';
import titleReducer from "../features/titleSlice/titleSlice";
export const store: any = configureStore({
reducer: {
title: titleReducer
},
});
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
first component:
import { useSelector, useDispatch } from "react-redux";
import { AppDispatch, RootState } from "../../../../redux/store/store";
const FirstComponent: FunctionComponent<FirstComponent> = (
props
) => {
const STATE_TITLE = useSelector((state: RootState) => state.title);
console.log(STATE_TITLE);
const dispatch = useDispatch<AppDispatch>();
const handleTitle = (e) => {
dispatch(SET_TITLE(e.target.value));
setTitle(e.target.value);
}
return (
<div>
<textarea
onChange={handleTitle} //works fine
/>
</div>
}
second component:
import { useSelector, useDispatch } from "react-redux";
import { AppDispatch, RootState } from "../../../../redux/store/store";
const SecondComponent: FunctionComponent<ISecondComponentProps> = (props) => {
const TITLE_STATE = useSelector((state: RootState) => state.title)
console.log(TITLE_STATE)
return (
<div>
{YOUR_TITLE} //this line happens error
</div>
)
and here is the error from development tab :
The error happens because your TITLE_STATE is an object and not a string. Try changing the return statement of the second component to
<div>
{TITLE_STATE?.title}
</div>
If this works, the error was because you were trying to render objects directly. And investigate why your textarea component returns an object instead of string as value, since that is the root cause here
This question already has answers here:
How do I create a GUID / UUID?
(70 answers)
Closed 12 months ago.
I am mapping an array of data with props into a component. Then onClick I pull some of that data into redux/reducer from the rendered items, trying to render the same data - but in a different spot on the page.
My problem is (I assume?) that the ID's are the same - I render data with keys's/id's that were already taken - while React wants unique ones.
I am not sure, if that's what's causing the problem - but I keep getting a warning that react wants unique key props.
(it's a shop app - on click, i want to add the chosen item to a cart with redux... )
Thoughts?
here I am building the component to render
import { useDispatch, useSelector } from 'react-redux'
import { add } from '../features/addToCart'
export const ReduxshopProps = (props) => {
const dispatch = useDispatch()
const handleAddToCart = (props) => {
dispatch(add(props));
};
return (<>
<div key={props.id} className='shopitem'>
<img src={props.url} />
<h2>{props.title}</h2>
<p className='boldprice'>${props.price}</p>
<button onClick={() => handleAddToCart(props) }
>
ADD TO CART
</button>
</div>
</>
)
}
here I am passing data into the component
import React from "react"
import { ReduxshopProps } from "./ReduxshopProps"
import shopdata from "./shopdata"
export default function ReduxShop() {
const cards = shopdata.map(props => {
return (
<ReduxshopProps
key={props.id}
title={props.title}
price={props.price}
url={props.url}
/>
)
})
return (
<div className='shopwrapper'>
<h1>TradingView Indicators</h1>
<div className='itemWrapper'>
{cards}
</div>
</div>
)
}
here's the REDUX code that pulls data from above
import { createSlice } from "#reduxjs/toolkit";
const initialState = {
cartItems: [],
cartTotalQuantity: 0,
cartTotalAmount: 0,
}
export const addToCartSlice = createSlice({
name: 'cart',
initialState,
reducers: {
add(state, action ) {
const itemIndex = state.cartItems.findIndex(
(item) => item.id === action.payload.id
);
if(itemIndex >= 0){
state.cartItems[itemIndex].cartQuantity += 1
} else {
const tempProduct = {...action.payload, cartQuantity: 1}
state.cartItems.push(tempProduct);
}
},
},
});
export const {add} = addToCartSlice.actions;
export default addToCartSlice.reducer;
and here I'm trying to render the data when someone clicks on a button.. onClick it acts as all components have the same ID - also I'm getting the key prop error from here, below
import React from 'react'
import { useSelector } from 'react-redux'
function Cart() {
const cart = useSelector((state) => state.cart)
return (
<div>
<h1>Cart</h1>
{cart.cartItems.map(cartItem => (
<div key={cartItem.id}>
<p>product : {cartItem.title}</p>
<p>price {cartItem.price}</p>
<p>quantity : {cartItem.cartQuantity}</p>
<p>url : <img src={cartItem.url} /></p>
</div>
))}
</div>
)
}
export default Cart
What you are trying to do is, assign UUID
First in terminal:
npm install uuid
Then:
import { v4 as uuidv4 } from 'uuid';
uuidv4(); // ⇨ '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d'
More on here, a sof thread: How to create a GUID / UUID
The library, on npm: https://www.npmjs.com/package/uuid
I've got a simple counter in react-redux which I am using to learn how to use these frameworks. I am trying to implement a pair of number inputs which determine the payload of an increment/decrement action pair.
The expected result is that I enter a number into both input fields, and when I click the increment/decrement buttons, the counter goes up or down by the specified amount. What is actually happening is that the increment button simply concatenates numbers onto the end of the counter value, whereas the decrement button behaves as expected. For example:
The expected behaviour here is that I will press + and the counter will go to 5, then if I pressed - it would go down to -5.
Here I have pressed + twice. As you can see, the counter has not gone up to 10 as you might expect, but instead 5 has been concatenated onto the value in the store, rather than added.
Here I have pressed - once. The leading zero has disappeared, and the number has gone down by 10 as expected.
The Code:
Being Redux, it is a bit boilerplate-y, but here is my code:
src/App.js:
import React from 'react';
import {useSelector, useDispatch} from 'react-redux';
import {increment, decrement} from './actions/counterActions';
function App() {
const counter = useSelector(state => state.counter);
const dispatch = useDispatch();
return (
<div className="App">
<h1>Counter: {counter}</h1>
<input type = "number" id = "incrementAmount"></input>
<br />
<input type = "number" id = "decrementAmount"></input>
<br />
<button onClick = {() => dispatch(increment(document.getElementById("incrementAmount").value))}>+</button>
<button onClick = {() => dispatch(decrement(document.getElementById("decrementAmount").value))}>-</button>
</div>
);
}
export default App;
src/index.js:
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { createStore } from 'redux';
import allReducers from './reducers/';
import { Provider } from 'react-redux';
const devToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__();
let store = createStore(allReducers, devToolsExtension);
store.subscribe(() => console.log("State: ", store.getState()));
ReactDOM.render(
<React.StrictMode>
<Provider store = {store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
src/actions/counterActions.js:
export const increment = (incrementAmount) => {
return {
type: "INCREMENT",
payload: incrementAmount
};
}
export const decrement = (decrementAmount) => {
return {
type: "DECREMENT",
payload: decrementAmount
};
}
src/actions/index.js:
import {combineReducers} from 'redux';
import counterReducer from './counterReducer'
const allReducers = combineReducers({counter: counterReducer});
export default allReducers;
src/reducers/counterReducer.js:
const counterReducer = (state = 0, action) => {
switch (action.type) {
case "INCREMENT":
return state + action.payload;
case "DECREMENT":
return state - action.payload;
default:
console.warn("Action type not recognised: ", action.type);
return state;
}
};
export default counterReducer;
So far I have tried using the Redux DevTools, which show that the state after pressing + is being treated as a string for some reason:
But I've got no idea why!
Any help would be much appreciated.
Cheers.
You should convert payload to number first:
return state + Number(action.payload);
Otherwise the result is a combined string.
Working sample: https://codesandbox.io/s/relaxed-minsky-ptcp3?file=/src/App.js
I keep getting the same error no matter what I do. Please give me the easiest solution possible.
import { Component } from "react";
import React from "react";
const NewsItem = (props) => {
// console.log(props.item);
const item = props.items.map((e) => {
return e.id;
});
console.log(props.items);
// console.log(props.items.title)
return <div>{item}</div>;
};
Try to use React PropTypes. Use your required schema definition for the prop item inside this. This will help the compiler to identify the type of the prop.
ComponentName.propTypes = {
items: PropTypes.arrayOf(arrayOf)
};
const NewsItem = ({ items = [] }) => {
const itemsList = items.map((item) => item.id);
return <div> { itemsList.join(', ') } </div>;
};
You are getting this errors because when you render the NewsItem the props items is not provide or it's provide with it value not an array. To avoid that you take advantage of propTypes and specify the default value of the props items when the NewsItem component is render without passing the props items.
const NewsItem = (props) => {
// other code goes here
return <div></div>
}
NewsItem.defaultProps = {
items: []
}
import { Component } from "react";
import React from "react";
const NewsItem = ({ items = [], ...props }) => {
// console.log(props.item);
const item = items.map((e) => {
return e.id;
});
console.log(items);
// console.log(props.items.title)
return <div>{item}</div>;
};
Obviously your error is in the caller of this component, the snippet above will replace ay undefined value in your props with the empty array.
To fix the error you will need to either fix the caller or handle the fact that items is not an array, maybe such as:
import { Component } from "react";
import React from "react";
const NewsItem = ({ items = [], ...props }) => {
if (!Array.isArray(items)) return <span>No items found</span>;
const item = items.map((e) => {
return e.id;
});
console.log(items);
// console.log(props.items.title)
return <div>{item}</div>;
};
I am kind of struggling to get the state of book, when I log the props I get book: undefined.
Any tips?
import React from 'react';
import { connect } from 'react-redux';
import BookForm from './BookForm';
const EditBook = (props) => {
console.log(props)
return (
<div>
hello
</div>
);
};
const mapStateToProps = (state, props) => {
return {
book: state.books.find((book) => book.id === props.match.params.id)
};
};
export default connect(mapStateToProps)(EditBook);
Rest of the project is on my Github: https://github.com/bananafreak/bookshelf
Update the Link in the BookListItem. You don't need the : before ${id}. The : is causing the problem.
<Link to={`/edit/${id}`}><h2>{title}</h2></Link>
In the EditBook component return the following
<BookForm {...props}></BookForm>
In the BookForm constructor set the state from props.book
this.state = { ...props.book }
I've ran into issues with this before where === will fail because the types of book.id and props.match.params.id are different. The params values are always strings - maybe try parseInt(props.match.params.id) or == comparison (with type coercion).
I managed to found where was my mistake.
In the component BookListItem:
import React from 'react';
import { Link } from 'react-router-dom';
const BookListItem = ({ author, title, genre, text, id, pages }) => (
<div>
<Link to={`/edit/${id}`}><h2>{title}</h2></Link>
<h3>by: {author}</h3>
<p>{genre}</p>
{pages > 0 && <p>{pages} pages</p>}
<p>{text}</p>
<p>-------------------------------</p>
</div>
);
export default BookListItem;
Before the ${id} I had unfortunately colon {/edit/:${id}} so then book.id and props.match.params.id could not match