Cannot read properties of undefined (reading 'buying') in redux-toolkit - javascript

Index.js
as You can see here the actions and store are being imported
> const store=require('./app/store')
> const cakeActions=require('./feature/cake/cakeSlice').cakeActions
> const icecreamActions=require('./feature/cake/cakeSlice').icecreamActions
>
> console.log("Initial State",store.getState())
> const unsubscribe=store.subscribe(()=>{
> console.log('Updated State',store.getState())
> })
>
> store.dispatch(cakeActions.ordered())
> store.dispatch(cakeActions.restocked(5))
>
> store.dispatch(icecreamActions.buying())
> store.dispatch(icecreamActions.restocking(7))
> unsubscribe()
Iceslice.js here slice function is being made for icecream slice
const createSlice=require('#reduxjs/toolkit').createSlice
const initialState={
no_of_icecream:10,
}
const icecreamSlice=createSlice({
name:'icecream',
initialState,
reducers:{
buying:(state)=>{
state.no_of_icecream--
},
restocking:(state,action)=>{
state.no_of_icecream+=action.payload
}
}
})
module.exports=icecreamSlice.reducer
module.exports.icecreamActions=icecreamSlice.actions
store.js store function is being made where reducer are being imported
const cakeReducer= require('../feature/cake/cakeSlice')
const icecreamReducer=require('../feature/icecream/iceSlice')
const store=configureStore({
reducer:{
cake:cakeReducer,
icecream:icecreamReducer,
}
})
module.exports=store

Related

Compressing an image-data string returned by captureVisibleTab (chrome api) and then edited by Konva

I have an extension which's taking a screenshot of a browser's tab. Later on, using Konva I'm editing the image and saving it in the following way:
When I print the image, it appears as the following:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABaAAAAOECAYAAABXTZbSAAAAAXNSR0IArs4c6QAAIABJREFUeF7snQeYJVWZ/t+quqnTJHKOgiQDSpiRICqKoitmzKvuuu7fALrrBjO7BgTDmuMGd03rGjEAMiQFUZSkiIKA...
and it continues with 587346 characters in total.
I'm attempting to compress the image. I was thinking of doing it using sharp, but it seems like they're not receiving image data string.
Any ideas how should I approach this?
Below is the component which was passed with the captureVisibleTab's return value (img data string):
// #ts-nocheck
import React from 'react';
import { Stage, Layer, Line, Image } from 'react-konva';
import { useState, useRef } from 'react';
import useImage from 'use-image';
import { Button, Stack, IconButton, Toolbar } from '#mui/material';
import useStackState from "#rooks/use-stack-state";
//import GestureIcon from '#mui/icons-material/Gesture';
import UndoIcon from '#mui/icons-material/Undo';
import RedoIcon from '#mui/icons-material/Redo';
import SaveIcon from '#mui/icons-material/Save';
type Props = {
imgSrc: string,
finishedEditing: (editedImg: string) => void;
}
function DrawingArea(props: Props) {
const imgSrc = props.imgSrc;
const finishedEditing = props.finishedEditing;
const [lines, setLines] = useState<any[]>([]);
const isDrawing = useRef(false);
const [image, imageSet] = useImage(imgSrc);
const [toRedo, toRedoSet] = useState(false);
const [toUndo, toUndoSet] = useState(false);
const [undoList, undoControls, undoStack] = useStackState([])
const { push, peek, pop, length } = undoControls;
const handleMouseDown = (e: any) => {
isDrawing.current = true;
const pos = e.target.getStage().getPointerPosition();
setLines([...lines, { points: [pos.x, pos.ay] }]);
};
const handleRedo = () => {
if (length === 0) {
console.log("empty stack - no redos");
return;
}
const elementToRedo = pop();
setLines((lines) => {
lines.push(elementToRedo)
return lines;
})
};
const handleClear = () => {
if (lines.length === 0) return;
setLines((lines) => {
lines = [];
return lines;
})
// need to empty redoStack
}
const handleUndo = () => {
if (lines.length < 1) return //empty lines - no undo action needed.
console.log(lines);
console.log(lines.length);
//pop into the stack
const poppedElement = lines[lines.length - 1];
undoControls.push(poppedElement); // for the redos
setLines((lines: any[]) => {
lines.pop();
return lines;
})
};
const handleMouseMove = (e: any) => {
// no drawing - skipping
if (!isDrawing.current) {
return;
}
const stage = e.target.getStage();
const point = stage.getPointerPosition();
// To draw line
let lastLine: any = lines[lines.length - 1];
if (lastLine) {
// add point
lastLine.points = lastLine.points.concat([point.x, point.y]);
// replace last
lines.splice(lines.length - 1, 1, lastLine);
setLines(lines.concat());
}
};
const handleMouseUp = () => {
isDrawing.current = false;
};
const stageRef = useRef(null);
const handleSave = async () => {
const dataURL = await stageRef.current.getStage().toDataURL();
console.log(dataURL);
finishedEditing(dataURL);
}
return (
<Stack>
<Stage
width={window.screen.width}
height={window.screen.height}
onMouseDown={handleMouseDown}
onMousemove={handleMouseMove}
onMouseup={handleMouseUp}
className="canvas-stage"
ref={stageRef}
>
<Layer>
<Image image={image} />
{lines.map((line: any, i: number) => (
<Line
key={i}
points={line.points}
stroke="#df4b26"
strokeWidth={2}
tension={0.5}
lineCap="round"
globalCompositeOperation={
line.tool === 'eraser' ? 'destination-out' : 'source-over'
}
/>
))}
</Layer>
</Stage>
<Toolbar sx={{ alignItems: "center" }}>
<IconButton onClick={() => { toUndoSet(!toRedo); handleUndo(); }}> <UndoIcon /> </IconButton>
<IconButton onClick={() => { toRedoSet(!toRedo); handleRedo(); }}> <RedoIcon /> </IconButton>
<IconButton onClick={handleSave}> <SaveIcon /> </IconButton>
<Button variant="contained" sx={{ width: "fit-content", alignItems: "flex-end" }} onClick={handleClear}>Clear</Button>
</Toolbar>
</Stack>
)
}
export default DrawingArea
Regards :_)

Filtering a todo list based on button clicked on React

I'm currently working on a to-do list app. Currently, I'm able to add, delete and edit the to-do list. I have a problem filtering my to-do list based on categories. The categories I have are all, active and completed. I'm stuck trying to filter the selected list based on the button clicked.
App.jsx:
import './App.css'
import Todo from './components/Todo';
import FilterButton from './components/FilterButton';
import Form from './components/form';
import { nanoid } from "nanoid";
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
});
return ref.current;
}
const filterMap = {
All: () => true,
Active: (task) => !task.completed,
Completed: (task) => task.completed
};
const filterNames = Object.keys(filterMap);
function App(props) {
const [tasks, setTasks] = useState(props.tasks);
const [filter, setFilter] = useState('ALL');
function toggleTaskCompleted(id) {
const updatedTasks = tasks.map((task) => {
// if this task has the same ID as the edited task
if (id === task.id) {
// use object spread to make a new object
// whose `completed` prop has been inverted
return {...task, completed: !task.completed}
}
return task;
});
setTasks(updatedTasks);
}
function deleteTask(id) {
const remainingTasks = tasks.filter((task) => id !== task.id);
setTasks(remainingTasks);
}
function editTask(id, newName) {
const editedTaskList = tasks.map((task) => {
// if this task has the same ID as the edited task
if (id === task.id) {
return {...task, name: newName}
}
return task;
});
setTasks(editedTaskList);
}
const taskList =tasks
.filter((filterNames[filter]))
.map((task)=> (
<Todo
id={task.id}
name={task.name}
completed={task.completed}
key={task.id}
toggleTaskCompleted={toggleTaskCompleted}
deleteTask={deleteTask}
editTask={editTask}
/>
));
const filterList = filterNames.map((name) => (
<FilterButton
key={name}
name={name}
isPressed={name === filter}
setFilter={setFilter}
/>
));
function addTask(name) {
const newTask = { id: `todo-${nanoid()}`, name, completed: true };
setTasks([...tasks, newTask]);
}
const tasksNoun = taskList.length !== 1 ? 'tasks' : 'task';
const headingText = `${taskList.length} ${tasksNoun} remaining`;
const listHeadingRef = useRef(null);
const prevTaskLength = usePrevious(tasks.length);
useEffect(() => {
if (tasks.length - prevTaskLength === -1) {
listHeadingRef.current.focus();
}
}, [tasks.length, prevTaskLength]);
return (
<div className="todoapp stack-large">
<h1>TodoApp</h1>
<Form addTask={addTask} />
<div className="filters btn-group stack-exception">
{filterList}
</div>
<h2 id="list-heading" tabIndex="-1" ref={listHeadingRef}>
{headingText}
</h2>
<ul
role="list"
className="todo-list stack-large stack-exception"
aria-labelledby="list-heading"
>
{taskList}
</ul>
</div>
);
}
export default App;
FilterButton
''import React from "react";
function FilterButton(props) {
return (
<button
type="button"
className="btn toggle-btn"
aria-pressed={props.isPressed}
onClick={() => props.setFilter(props.name)}
>
<span className="visually-hidden">Show </span>
<span>{props.name}</span>
<span className="visually-hidden"> tasks</span>
</button>
);
}
export default FilterButton; ```
You're passing filterName that actually only contains the keys, not the method. Also, make sure you're getting tasks as an array from props.
Update your state as well to
const [tasks, setTasks] = useState(props.tasks || [] );
const taskList = useMemo(()=>tasks
.filter(filterMap[filter])
.map((task)=> (
<Todo
.....
/>
)),[tasks,filter]);
Also just wrap your taskList with useMemo so whenever tasks & filter change your taskList will be updated.

React.js Functional Component Localhost Problem

So my page is an Author page which shows different authors and their details in each card which I fetched from API and then mapped.
https://i.stack.imgur.com/eSD7u.png
And in each card after onclick it changes to Remove Favourite. The card which is favourited makes the idfav true in the object array of the author state and false if not favourited. And there is a 2nd page which shows all the favourite authors. Now I am passing it down first as localstorage for the author state but it seems after my 2nd reload if I click on the button irrespective of whether or not the button is add or remove all the other cards/array is removed and only the card on which button I selected shows up.
const [author, setAuthor] = useState([]);
const [AuthorTempState, setAuthorTempState] = useState([]);
// pagination calculation
const [PageNumber, setPageNumber] = useState(0);
const [Postsperpage] = useState(4);
const PagesVisited = PageNumber * Postsperpage;
const pageCount = Math.ceil(author.length / Postsperpage);
const changePage = ({ selected }) => {
setPageNumber(selected);
}
const getAuthors = async () => {
const res = await fetch(`https://api.quotable.io/authors?limit=30`);
const data = await res.json();
for (const element of data.results) {
element.idfav = false;
}
data.results.sort((a, b) => (a._id > b._id) ? 1 : -1)
setAuthor(data.results);
setAuthorTempState(data.results);
}
const saveAuth = () => {
localStorage.setItem('authors', JSON.stringify(author));
}
const getAuth = () => {
const newAuthors = JSON.parse(localStorage.getItem('authors'));
if (newAuthors && newAuthors.length > 0) {
setAuthor(newAuthors);
} else {
getAuthors();
}
}
useEffect(() => {
// console.log((author));
if (author.length === 0) {
getAuth();
}
saveAuth();
}, [author]);
const favBttn = (Auth) => {
const filterData = AuthorTempState.filter(data => data._id !== Auth._id)
Auth.idfav = true;
const updateAuthor = [Auth, ...filterData]
updateAuthor.sort((a, b) => (a._id > b._id) ? 1 : -1)
setAuthor(updateAuthor)
}
const remfavBttn = (Auth) => {
const filterData = AuthorTempState.filter(data => data._id !== Auth._id)
Auth.idfav = false;
const updateAuthor = [Auth, ...filterData]
updateAuthor.sort((a, b) => (a._id > b._id) ? 1 : -1)
setAuthor(updateAuthor);
}
const Author = author.slice(PagesVisited, PagesVisited + Postsperpage)
return (
<div className="AppWhole">
<AuthorSidebar />
<div className="App">
<div className="author">
{Author.map(
(Author) => (
<div className="authors" key={Author._id}>
{
(Author.idfav) ? (<button className='right' onClick={() => {
remfavBttn(Author);
}}>Remove Favt.</button >) : (<button className='right' onClick={() => {
favBttn(Author);
}}>Add Favt.</button >)
}
<p>Name: {Author.name}</p>
<p>Bio: {Author.bio}</p>
<p>Wiki: <a href='{Author.link}'>{Author.link}</a></p>
</div>
))}
<div id='pageauthor'>
<ReactPaginate
pageCount={pageCount}
onPageChange={changePage}
previousLabel={"<<"}
nextLabel={">>"}
containerClassName={'paginationLinks'}
disabledClassName={'paginationDisabled'}
activeClassName={'paginationActive'}
/>
</div>
</div>
</div>
</div>
);
}
export default Authors;
Please help me I have been stuck on this for a week. Thank you.
Okay, once I read your entire code and then read your issue made it pretty clear what's wrong. The issue is here
const favBttn = (Auth) => {
// notice that you are using AuthorTempState to filter data
// but do you remember initialising it when the data is found in local storage?
// AuthorTempState is currently an empty array.
const filterData = AuthorTempState.filter(data => data._id !== Auth._id)
Auth.idfav = true;
const updateAuthor = [Auth, ...filterData]
updateAuthor.sort((a, b) => (a._id > b._id) ? 1 : -1)
setAuthor(updateAuthor)
}

React App becomes blank when I try to update an array in the state

I am trying to manipulate the images shown in my React App by voice. I implemented the SR, which works fine:
<button onClick={SpeechRecognition.startListening}>Start</button>
I have an array of loadImages in my state, which is empty first:
const [loadImages, setLoadImages] = React.useState([]);
Whenever the word spoken is "kitten", the array of loadImages gets updated in this way:
if(transcript == "kitten")
{
const newImages = loadImages.concat({image: 'https://www.onlinekittencare.com/wp-content/uploads/2020/07/vChK6pTy3vN3KbYZ7UU7k3-1200-80.jpg'})
setLoadImages(newImages);
}
The transcript you see is a variable, which I initialized here:
const {transcript} = useSpeechRecognition();
In the render I use it to show what the SR understood, so if I say "hello" it shows "hello":
<p id="transcript">Transcript: {transcript}</p>
And this is where the images in loadImages show up:
{images.map((image) => {
return <URLImage image={image}/>;
})}
The problem is that whenever I say "kitten", which as stated above is used as a command to add the picture to the array loadImages, my React App gets blank. In the inspect I can also see that it says react-dom.development.js:14997 Uncaught Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
How do I fix that?
EDIT (I added the whole code):
function App() {
const [rectangles, setRectangles] = useState([]);
const [circles, setCircles] = useState([]);
const [selectedId, selectShape] = useState(null);
const [shapes, setShapes] = useState([]);
const [, updateState] = React.useState();
const stageEl = React.createRef();
const layerEl = React.createRef();
const fileUploadEl = React.createRef();
const [brushSize, setBrushSize] = React.useState('5');
const [isDrawing, setIsDrawing] = React.useState(false);
const dragUrl = React.useRef();
//const stageRef = React.useRef();
const [images, setImages] = React.useState([]);
const [loadImages, setLoadImages] = React.useState([]);
const getRandomInt = max => {
return Math.floor(Math.random() * Math.floor(max));
};
const {transcript} = useSpeechRecognition();
const URLImage = ({image}) => {
const [img] = useImage(image.src);
return (
<Image
image = {img}
x = {image.x}
y = {image.y}
offsetX = {50}
offsetY = {50}
width={200}
height={200}
draggable
/>
);
};
const drawLine = () => {
setIsDrawing(true);
if(isDrawing){
addLine(stageEl.current.getStage(), layerEl.current, brushSize);
};
};
const eraseLine = () => {
addLine(stageEl.current.getStage(), layerEl.current, brushSize, "erase");
};
const addRectangle = () => {
setIsDrawing(false);
const rect = {
x: getRandomInt(100),
y: getRandomInt(100),
width: 100,
height: 100,
fill: "red",
id: `rect${rectangles.length + 1}`,
};
const rects = rectangles.concat([rect]);
setRectangles(rects);
const shs = shapes.concat([`rect${rectangles.length + 1}`]);
setShapes(shs);
};
const forceUpdate = React.useCallback(() => updateState({}), []);
const undo = () => {
const lastId = shapes[shapes.length - 1];
let index = circles.findIndex(c => c.id == lastId);
if (index != -1) {
circles.splice(index, 1);
setCircles(circles);
}
index = rectangles.findIndex(r => r.id == lastId);
if (index != -1) {
rectangles.splice(index, 1);
setRectangles(rectangles);
}
index = images.findIndex(r => r.id == lastId);
if (index != -1) {
images.splice(index, 1);
setImages(images);
}
shapes.pop();
setShapes(shapes);
forceUpdate();
};
document.addEventListener("keydown", ev => {
if (ev.code == "Delete") {
let index = circles.findIndex(c => c.id == selectedId);
if (index != -1) {
circles.splice(index, 1);
setCircles(circles);
}
index = rectangles.findIndex(r => r.id == selectedId);
if (index != -1) {
rectangles.splice(index, 1);
setRectangles(rectangles);
}
index = images.findIndex(r => r.id == selectedId);
if (index != -1) {
images.splice(index, 1);
setImages(images);
}
forceUpdate();
}
});
if(transcript == "kitten")
{
const newImages = loadImages.concat({image: 'https://www.onlinekittencare.com/wp-content/uploads/2020/07/vChK6pTy3vN3KbYZ7UU7k3-1200-80.jpg'})
setLoadImages(newImages);
}
return (
<div className="home-page">
{loadImages.map(image => (
<img id="img" className="img"
src={image.image}
width="200"
height="200"
onDragStart={(e) => {
dragUrl.current = e.target.src;}}
/>
))}
<div
onDrop={(e) => {
e.preventDefault();
// register event position
stageEl.current.setPointersPositions(e);
// add image
setImages(
images.concat([
{
...stageEl.current.getPointerPosition(),
src: dragUrl.current,
},
])
);
}}
onDragOver={(e) =>
e.preventDefault()
}
>
<h1>Whiteboard</h1>
<button onClick={addRectangle}>
Rectangle
</button>
<button>
Circle
</button>
<button onClick={drawLine}>
Line
</button>
<button onClick={eraseLine}>
Erase
</button>
<select
value={brushSize}
onChange={(e) => {
setBrushSize(e.target.value);
drawLine();
}}
>
<option value="5">5</option>
<option value="20">20</option>
<option value="50">50</option>
</select>
<button variant="secondary">
Text
</button>
<button variant="secondary">
Image
</button>
<button variant="secondary" onClick={undo}>
Undo
</button>
<p id="transcript">Transcript: {transcript}</p>
<button onClick={SpeechRecognition.startListening}>Start</button>
<Stage
width={window.innerWidth * 0.9}
height={window.innerHeight - 150}
ref={stageEl}
dragabble
onMouseDown={e => {
// deselect when clicked on empty area
const clickedOnEmpty = e.target === e.target.getStage();
if (clickedOnEmpty) {
selectShape(null);
}
}}
>
<Layer ref={layerEl}>
{rectangles.map((rect, i) => {
return (
<Rectangle
key={i}
shapeProps={rect}
isSelected={rect.id === selectedId}
//onSelect={() => {
// selectShape(rect.id);
//}}
onChange={newAttrs => {
const rects = rectangles.slice();
rects[i] = newAttrs;
setRectangles(rects);
}}
/>
);
})}
{images.map((image) => {
return <URLImage image={image}/>;
})}
</Layer>
</Stage>
</div>
</div>
);
}
export default App;
Based on the code you've shared, it has to do with how you're updating the state if the transcript is equal to kitten.
Essentially, the logic you've written says, on render, if the transcript is kitten, update the state. BUT, when you update the state, that will re-render, and hit that logic again... and again... and again. The solution here is to wrap that in a useEffect – React Docs explain it best but in simple terms, you want to "do something" as a side effect of "something else".
In this case, if the transcript updates, you want to check the state of transcript, and if it meets a condition, you want to update your state:
React.useEffect(() => {
if (transcript === "kitten") {
const newImages = loadImages.concat({image: 'https://www.onlinekittencare.com/wp-content/uploads/2020/07/vChK6pTy3vN3KbYZ7UU7k3-1200-80.jpg'})
setLoadImages(newImages);
}
}, [transcript]);
The final piece to the useEffect is a dependency array ([transcript])–this dictates to React which item you want to watch for changes in–if transcript changes, it will run your effect and only when it changes, instead of every time it renders.

How to calculate my transactions according to ID?

I have an application that is an expense tracker simulation.
What I need to do is to calculate my transactions according to the UUID of the account that I pass when registering a new transaction.
At the moment, all my calculations are being saved in the same account. How do I correctly group and calculate my transactions?
The project has a lot of files, so I put it on the codesandbox.io
In the image, you can see that I made 4 transactions, with 3 different accounts, but the calculations are done as if there was a single account
My ContextApi:
import React from "react";
import PropTypes from "prop-types";
const AppContext = React.createContext();
const initialState = {
transactions: [],
};
const reducer = (state, action) => {
switch (action.type) {
case "ADD_TRANSACTION":
return {
...state,
transactions: [action.payload, ...state.transactions],
};
default:
return state;
}
};
const AppContextProvider = ({ children }) => {
const [state, dispatch] = React.useReducer(reducer, initialState);
return (
<AppContext.Provider value={{ state, dispatch }}>
{children}
</AppContext.Provider>
);
};
AppContextProvider.propTypes = {
children: PropTypes.node.isRequired,
};
export { AppContext, AppContextProvider };
My list of transactions:
import React from "react";
import { AppContext } from "../../providers/app";
const Transaction = ({ transaction }) => {
const { state } = React.useContext(AppContext);
const amounts = state.transactions.map((transaction) => transaction.amount);
const balance = amounts.reduce((acc, item) => (acc += item), 0);
const sign = transaction.amount < 0 ? "-" : "";
return (
<div className="transaction">
<div>
<span>
<strong>
{transaction.amount > 0 ? "Transferred" : "Withdrew"} $
{Math.abs(transaction.amount)}{" "}
</strong>{" "}
{transaction.amount > 0 ? "to " : "from "}
<strong>{transaction.account}</strong>.
</span>
</div>
<div>
<span>
Current <strong>{transaction.account}</strong>'s balance is{" "}
<strong>
{sign}${Math.abs(balance)}
</strong>
.
</span>
</div>
</div>
);
};
export default Transaction;
Calculate the balance for one transaction:
const balance = state.transactions.reduce( (accu, ta) => {
return ta.account !== transaction.account
? accu
: accu + ta.amount;
}, 0);
Alternatively, you can create a balanceByAccount map:
const balanceByAccount = state.transactions.reduce( (acc, item) => {
const newAmount = ( acc[ item.account ] || 0 ) + item.amount;
return {
...acc,
[item.account]: newAmount
};
}, {});
Then you can get the balance for one account with e.g.:
balanceByAccount[ transaction.account ]

Categories

Resources