How do I create a delete/clear button in REACT js? - reactjs

Hi I'm new to REACT and I have a HW where I need to create a grocery shopping list and I need to create a clear button. The isPurchased key value pair is a boolean though. I need to create a button that when I click Purchased it clears that grocery item off my list. Any help would be appreciated.
class App extends Component {
state = {
grocery: grocery,
item: '',
brand: '',
units: Number,
quantity: Number,
isPurchased: Boolean
}
handleChange = (e) => {
this.setState({ [e.target.id]: e.target.value })
}
handleSubmit = (e) => {
e.preventDefault()
const addGrocery = {
item: this.state.item,
brand: this.state.brand,
units: this.state.units,
quantity: this.state.quantity,
}
this.setState({
grocery: [addGrocery, ...this.state.grocery],
item: '',
brand: '',
units: Number,
quantity: Number,
})
const removeGrocery = {
item: this.state.item
}
}

hey here is a full code for creating a to do list in react (it will be very similar to your problem):
**
Summary
** of the idea of creating a to-do list or shopping list is that each to-do will be an object, when we create a new object we will insert it into an array. once it is in the array by using the array.map() function we will convert each object to an HTML element to make the UI.
if something is unclear I am here to answer
file - App.js:
import React, { useState, useReducer } from "react";
import Todo from "./Todo";
export const ACTIONS = {
ADD_TODO: "add-todo",
TOGGLE_TODO: "toggle-todo",
DELETE_TODO: "delete-todo",
};
function reducer(todos, action) {
switch (action.type) {
case ACTIONS.ADD_TODO:
return [...todos, newTodo(action.payload.name)];
case ACTIONS.TOGGLE_TODO:
return todos.map((todo) => {
if (todo.id === action.payload.id) {
return { ...todo, complete: !todo.complete }; //change to complete if we found to id that toggled
}
return todo;
});
case ACTIONS.DELETE_TODO:
return todos.filter((todo) => todo.id !== action.payload.id);
default:
return todos;
}
}
function newTodo(name) {
return { id: Date.now(), name: name, complete: false };
}
const App = () => {
const [todos, dispatch] = useReducer(reducer, []); //useReducer return the state and the reducer function
const [name, setName] = useState("");
function handleSubmit(e) {
e.preventDefault();
dispatch({ type: ACTIONS.ADD_TODO, payload: { name: name } });
setName("");
}
return (
<>
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</form>
{todos.map((todo) => {
return <Todo key={todo.id} todo={todo} dispatch={dispatch} />;
})}
</>
);
};
export default App;
Another file (component) - Todo.js:
import React from "react";
import { ACTIONS } from "./App";
const Todo = ({ todo, dispatch }) => {
return (
<div>
<span style={{ color: todo.complete ? "#AAA" : "#000" }}>
{todo.name}
</span>
<button
onClick={() =>
dispatch({ type: ACTIONS.TOGGLE_TODO, payload: { id: todo.id } })
}
>
Toggle
</button>
<button
onClick={() =>
dispatch({ type: ACTIONS.DELETE_TODO, payload: { id: todo.id } })
}
>
Delete
</button>
</div>
);
};
export default Todo;

Related

Iam making a Todo using (useReducer and useContext) but the update functionality is not working please check this out

This is my App.jsx , where iam displaying all the todos, after clicking edit the input gets the value of selected todo and while changing the value and clicking on update it does nothing.
export default function App() {
const { dispatch, state } = useContext(todoContext);
const [todo, setTodo] = useState("");
const [isEditing, setIsEditing] = useState(false);
const [selectedTodo, setSelectedTodo] = useState("");
const handleSubmit = (e) => {
const id = uuidv4();
e.preventDefault();
if (!isEditing) {
dispatch({
type: "ADD_TODO",
payload: { id: id, text: todo },
});
setTodo("");
} else {
dispatch({
type: "UPDATE_TODO",
payload: selectedTodo,
});
setIsEditing(false);
setTodo("");
}
};
const handleEdit = (val) => {
setIsEditing(true);
const item = state.todos.find((todo) => todo.id === val.id);
setTodo(item.text);
setSelectedTodo(item);
};
return (
<div className="App">
<br />
<h1>Hello World This is Todo App</h1>
<br />
<form onSubmit={handleSubmit}>
<input
value={todo}
onChange={(e) => setTodo(e.target.value)}
type="text"
placeholder="Enter a todo"
/>
<button>{isEditing ? "Update" : "Submit"}</button>
</form>
{state.todos.map((item) => (
<div key={item.id} className="todoitem">
<p
onClick={() => dispatch({ type: "TOGGLE_TODO", payload: item.id })}
style={{
cursor: "pointer",
textDecoration: item.completed ? "line-through" : "",
}}
>
{item.text}
</p>
<span
onClick={() => dispatch({ type: "REMOVE_TODO", payload: item.id })}
>
×
</span>
<button onClick={() => handleEdit(item)}>Edit</button>
</div>
))}
</div>
);
}
This is my reducers (todoReducer.jsx) , where the upadte functionality doesnot work when i click edit to change the value and click update it does nothing
export const INITIAL_STATE = {
todos: [],
updated: [],
};
export const reducer = (state, action) => {
switch (action.type) {
case "ADD_TODO":
return {
...state,
todos: [...state.todos, action.payload],
};
case "REMOVE_TODO": {
return {
...state,
todos: state.todos.filter((item) => item.id !== action.payload),
};
}
case "TOGGLE_TODO":
return {
...state,
todos: state.todos.map((todo) =>
todo.id === action.payload
? { ...todo, completed: !todo.completed }
: todo
),
};
case "UPDATE_TODO":
return {
...state,
todos: state.todos.map((todo) => {
if (todo.id === action.payload.id) {
return action.payload;
}
return todo;
}),
};
default:
return state;
}
};
you need to update text with latest text
selectedTodo has old data
todo have new text
in your handleSubmit please update below code
dispatch({
type: "UPDATE_TODO",
payload: { ...selectedTodo, text: todo },
});

Is there a way to handle state in a form that is dynamically built based off of parameters sent from the back end

I have a page in react 18 talking to a server which is passing information about how to build specific elements in a dynamic form. I am trying to figure out how to manage state in a case where there are multiple selects/multiselects in the page. Using one hook will not work separately for each dropdown field.
Code is updated with the latest updates. Only having issues with setting default values at this point. Hooks will not initially set values when given.
import { Calendar } from 'primereact/calendar';
import { Dropdown } from 'primereact/dropdown';
import { InputSwitch } from 'primereact/inputswitch';
import { InputText } from 'primereact/inputtext';
import { MultiSelect } from 'primereact/multiselect';
import React, { useEffect, useState, VFC } from 'react';
import { useLocation } from 'react-router-dom';
import { useEffectOnce } from 'usehooks-ts';
import { useAppDispatch, useAppSelector } from 'redux/store';
import Form from '../components/ReportViewForm/Form';
import { getReportParamsAsync, selectReportParams } from '../redux/slice';
export const ReportView: VFC = () => {
const location = useLocation();
const locState = location.state as any;
const dispatch = useAppDispatch();
const reportParams = useAppSelector(selectReportParams);
const fields: JSX.Element[] = [];
const depList: any[] = [];
//const defaultValList: any[] = [];
//dynamically setting state on all dropdown and multiselect fields
const handleDdlVal = (name: string, value: string) => {
depList.forEach((dep) => {
if (name === dep.dependencies[0]) {
dispatch(getReportParamsAsync(currentMenuItem + name + value));
}
});
setState((prev: any) => {
return { ...prev, [name]: value };
});
};
//dynamically setting state on all calendar fields
const handleCalVal = (name: string, value: Date) => {
setState((prev: any) => {
return { ...prev, [name]: value };
});
};
//dynamically setting state on all boolean fields
const handleBoolVal = (name: string, value: boolean) => {
setState((prev: any) => {
return { ...prev, [name]: value };
});
};
/* function getInitVals(values: any) {
const defaultList: any[] = [];
values.forEach((param: any) => {
defaultList.push({ name: param.name, value: param.defaultValues[0] });
});
} */
const [state, setState] = useState<any>({});
const [currentMenuItem, setCurrentMenuItem] = useState(locState.menuItem.id.toString());
useEffectOnce(() => {}), [];
useEffect(() => {
if (reportParams?.length === 0) {
dispatch(getReportParamsAsync(currentMenuItem));
}
//reload hack in order to get page to load correct fields when navigating to another report view
if (currentMenuItem != locState.menuItem.id) {
window.location.reload();
setCurrentMenuItem(locState.menuItem.id.toString());
}
}, [dispatch, reportParams, currentMenuItem, locState, state]);
//dependency list to check for dependent dropdowns, passed to reportddl
reportParams.forEach((parameter: any) => {
if (parameter.dependencies !== null && parameter.dependencies[0] !== 'apu_id') {
depList.push(parameter);
}
});
//filter dispatched data to build correct fields with data attached.
reportParams.forEach((parameter: any, i: number) => {
if (parameter.validValuesQueryBased === true) {
if (parameter.validValues !== null && parameter.multiValue) {
const dataList: any[] = [];
parameter.validValues.map((record: { value: any; label: any }) =>
dataList.push({ id: record.value, desc: record.label }),
);
fields.push(
<span key={i} className='p-float-label col-12 mx-3 field'>
<MultiSelect
options={dataList}
name={parameter.name}
value={state[parameter.name]}
onChange={(e) => handleDdlVal(parameter.name, e.value)}
></MultiSelect>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
} else if (parameter.validValues !== null) {
const dataList: any[] = [];
parameter.validValues.map((record: { value: any; label: any }) =>
dataList.push({ id: record.value, desc: record.label }),
);
fields.push(
<span key={i} className='p-float-label col-12 mx-3 field'>
<Dropdown
options={dataList}
optionValue='id'
optionLabel='desc'
name={parameter.name}
onChange={(e) => handleDdlVal(parameter.name, e.value)}
value={state[parameter.name]}
//required={parameter.parameterStateName}
placeholder={'Select a Value'}
></Dropdown>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
}
} else if (parameter.parameterTypeName === 'Boolean') {
fields.push(
<span key={i} className='col-12 mx-3 field-checkbox'>
<InputSwitch
checked={state[parameter.name]}
id={parameter.id}
name={parameter.name}
onChange={(e) => handleBoolVal(parameter.name, e.value)}
></InputSwitch>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
} else if (parameter.parameterTypeName === 'DateTime') {
//const date = new Date(parameter.defaultValues[0]);
fields.push(
<span key={i} className='p-float-label col-12 mx-3 field'>
<Calendar
value={state[parameter.name]}
name={parameter.name}
onChange={(e) => {
const d: Date = e.value as Date;
handleCalVal(parameter.name, d);
}}
></Calendar>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
} else if (parameter.name === 'apu_id') {
return null;
} else {
fields.push(
<span key={i} className='p-float-label col-12 mx-3 field'>
<InputText name={parameter.name}></InputText>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
}
});
const onSubmit = () => {
console.log(state);
};
return (
<Form onReset={null} onSubmit={onSubmit} initialValues={null} validation={null} key={null}>
{fields}
</Form>
);
};
enter code here

What is causing the following Firestore error in ReactJS? Function DocumentReference .update() called with invalid data. Unsupported field value:

There seems to be something wrong with the way I update state, as it gets overwritten...
import Servis from "./funkc/servisni";
import React, { useState, useEffect } from "react";
export default function ContactUpdate(props) {
const initialState = {
ime: props.item.Ime,
prezime: props.item.Prezime,
datum: props.item.Datum,
kontakt: props.item.Kontakt,
published: props.item.Published,
id: props.Id,
};
const [theItem, setTheItem] = useState();
const [message, setMessage] = useState();
useEffect(() => {
setTheItem(props.item);
console.log(theItem);
}, []);
const handleInputChange = (event) => {
const { name, value } = event.target;
setTheItem({ ...theItem, [name]: value });
console.log(theItem, props.Id);
};
the problem seems to be in the following:
const updateItem = (theItem) => {
let data = {
Ime: theItem.Ime,
Prezime: theItem.Prezime,
Kontakt: theItem.Kontakt,
Datum: theItem.Datum,
Published: true,
Id: theItem.id,
};
Servis.update(theItem.id, data)
.then(() => {
setMessage("Uspjesno ste izmijenili unos!");
})
.catch((e) => {
console.log(e);
});
};
as visible in the console.log
return (
<div className="container">
{console.log(("theItem", props.Id, theItem))}
{theItem ? (
<div className="edit-form">
<h4>Kontakt</h4>
...
<button type="submit" onClick={updateItem}>
Update
</button>
<p>{message}</p>
</div>
) : (
<div>
<br />
<p>Odaberi jedan broj...</p>
</div>
)}{" "}
</div>
);
}
The call on the updateItem function by clicking on the 'Update' button results in the error : Function DocumentReference .update() called with invalid data. Unsupported field value...
Resolved through being careful about naming variables...
</div>
<ContactUpdate item={item} id={theId} />
</div>
and then
const updateItem = () => {
let data = {
Ime: theItem.Ime,
Prezime: theItem.Prezime,
Kontakt: theItem.Kontakt,
Datum: theItem.Datum,
published: true,
id: props.id,
};
Servis.update(props.id, data)
.then(() => {
setMessage("Uspjesno ste izmijenili unos!");
})
.catch((e) => {
console.log(e);
});
};

On button click check the checkbox and add the data into cart in react redux?

In this problem what can I do so that the on clicking the button, both the function add to the cart and select the checkbox executes together? In the current scenario add to cart is working when the button is clicked but the checkbox isn't selected. I removed all the styles so that the actual code is readable
YourItems.js
import React from "react";
import { connect } from "react-redux";
import { addOn } from "./data";
import { addOnhandleChange,addOnSelector} from "./AddOnActions";
const YourItems = ({ addOnhandleChange, addOnSelector, selectedId }) => {
return (
<div>
{addOn.map(({ id, name, img, price, unit }) => {
return (
<div key={id}>
<div>
<img src={img} alt={name} />
<p>{name}</p>
<span>Rs. {price}</span>
<input
type="checkbox"
checked={id === selectedId}
onChange={() => addOnhandleChange(id)}
/>
</div>
<button onClick={() =>addOnSelector({id, name,img,price,unit, })}>
Add
</button>
</div>
)})}
</div>
);
};
const mapStateToProps = (state) => {
return {
selectedId: state.addOn.selectedId,
};
};
export default connect(mapStateToProps, { addOnSelector,addOnhandleChange})(YourItems);
AddOnAction.js
export const addOnhandleChange = (id) => (dispatch) => {
dispatch({
type: "SELECTED_ID",
payload: id,
});
};
export const addOnSelector = ({ id, name, img, price, unit }) => (dispatch) => {
dispatch({
type: "ADD_TO_CART",
payload: { id, name, img, price, unit },
});
};
reducer.js
const initialState = {
selectedId: "",
};
export default function SelectorReducer(
state = initialState,
action
) {
switch (action.type) {
case "SELECTED_ID":
return {
...state,
selectedId: action.payload,
};
default:
return state;
}
}
data.js
export const addOn = [
{
id: 12654,
img: "https://images.pexels.com/photos/1132047/pexels-photo-1132047.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
name: "Banana",
price: 10,
unit: 1,
},
{
id: 2256435,
img: "https://images.pexels.com/photos/1132047/pexels-photo-1132047.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
name: "Mango",
price: 20,
unit: 1,
},
{
id: 3429684,
img: "https://images.pexels.com/photos/1132047/pexels-photo-1132047.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940",
name: "Grape",
price: 30,
unit: 1,
},
];
Add a case for "ADD_TO_CART" action type and use the id packed in action.payload in the reducer.
export default function SelectorReducer(
state = initialState,
action
) {
switch (action.type) {
case "SELECTED_ID":
return {
...state,
selectedId: action.payload,
};
case "ADD_TO_CART":
return {
...state,
selectedId: action.payload.id, // <-- use the payload.id
};
default:
return state;
}
}

Is it a valid way to write redux actions and reducer?

I've built a cards war game. I'm new to redux and wonder if I use it the correct way, especially when I declare actions in the Game and Main components, and use action's payloads as callbacks to update the state. Also, It feels like a lot of code for a small app. Maybe you can help guys and give me some insights if i'm doing it the wrong way and why, thanks. I put here the relevant components and the full code is here:
https://github.com/morhaham/cards-war-redux
store.js:
import { createStore } from "redux";
const state = {
game_ready: false,
cards: [],
player: { name: "", cards: [], points: 0 },
computer: { name: "computer", cards: [], points: 0 },
};
const reducer = (state, action) => {
switch (action.type) {
case "INIT_GAME_CARDS":
return action.payload(state);
case "UPDATE_PLAYER_NAME":
return action.payload(state);
case "SET_GAME_READY":
return action.payload(state);
case "DIST_CARDS":
return action.payload(state);
case "SET_NEXT_CARDS":
return action.payload(state);
case "INCREASE_POINTS":
return action.payload(state);
case "RESET_GAME":
return action.payload(state);
default:
return state;
}
};
const store = createStore(reducer, state);
export default store;
Main.js:
import React, { useEffect } from "react";
import { Button } from "#material-ui/core";
import { useHistory } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { NUM_OF_CARDS, MAX_CARD_VALUE } from "./constants";
import { shuffle } from "./helpers";
// action creator to initialize the game
const initGameCards = () => ({
type: "INIT_GAME_CARDS",
payload: (state) => {
// creates an array of size 52 filled with 1..13 four times
const cards = Array(NUM_OF_CARDS / MAX_CARD_VALUE)
.fill(
Array(13)
.fill()
.map((_, i) => i + 1)
)
.flat();
// shuffle the cards
shuffle(cards);
return {
...state,
cards,
};
},
});
// action creator to control the player's name
const updatePlayerName = (name) => ({
type: "UPDATE_PLAYER_NAME",
payload: (state) => ({
...state,
player: { ...state.player, name: name },
}),
});
const setGameReady = () => ({
type: "SET_GAME_READY",
payload: (state) => ({
...state,
game_ready: true,
}),
});
function Main() {
const history = useHistory();
const dispatch = useDispatch();
const player = useSelector(({ player }) => player);
// const game_ready = useSelector(({ game_ready }) => game_ready);
const handleClick = React.useCallback(
(e) => {
e.preventDefault();
if (player.name) {
dispatch(setGameReady());
history.replace("./game");
}
},
[dispatch, player.name]
);
useEffect(() => {
dispatch(initGameCards());
}, []);
const handleChange = React.useCallback((e) => {
const target = e.target;
const val = target.value;
switch (target.id) {
case "playerName":
dispatch(updatePlayerName(val));
break;
default:
break;
}
});
return (
<div>
{/* check for valid input */}
<form>
<label htmlFor="playerName">
<h1 className="text-blue-800 text-5xl text-shadow-lg mb-3">
Ready for war
</h1>
</label>
<input
className="border focus:ring-2 focus:outline-none"
id="playerName"
required
onChange={handleChange}
placeholder="Enter your name"
type="text"
value={player.name}
/>
{!player.name ? (
<p className="text-red-700">Please fill the field</p>
) : (
""
)}
<Button
onClick={handleClick}
type="submit"
color="primary"
variant="contained"
>
Start
</Button>
</form>
</div>
);
}
export default Main;
Game.js:
import { Button } from "#material-ui/core";
import React from "react";
import { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { useHistory } from "react-router-dom";
import { NUM_OF_CARDS } from "./constants";
import { shuffle } from "./helpers";
// action creator to distribute the cards at the beginning of the game
const distCards = () => ({
type: "DIST_CARDS",
payload: (state) => {
const cards = [...state.cards];
shuffle(cards);
const computer_cards = cards.slice(0, NUM_OF_CARDS / 2);
const player_cards = cards.slice(NUM_OF_CARDS / 2);
const computer_current_card = computer_cards.pop();
const player_current_card = player_cards.pop();
return {
...state,
cards,
// distributes cards evenly
computer: {
...state.computer,
cards: computer_cards,
current_card: computer_current_card,
points: 0,
},
player: {
...state.player,
cards: player_cards,
current_card: player_current_card,
points: 0,
},
};
},
});
const setNextCards = () => ({
type: "SET_NEXT_CARDS",
payload: (state) => {
let [computer_cards, player_cards] = [
[...state.computer.cards],
[...state.player.cards],
];
const [computer_next_card, player_next_card] = [
computer_cards.pop(),
player_cards.pop(),
];
return {
...state,
player: {
...state.player,
cards: player_cards,
current_card: player_next_card,
},
computer: {
...state.computer,
cards: computer_cards,
current_card: computer_next_card,
},
};
},
});
const pointsIncreament = () => ({
type: "INCREASE_POINTS",
payload: (state) => {
const [player_current_card, computer_current_card] = [
state.player.current_card,
state.computer.current_card,
];
return {
...state,
player: {
...state.player,
points:
player_current_card > computer_current_card
? state.player.points + 1
: state.player.points,
},
computer: {
...state.computer,
points:
player_current_card < computer_current_card
? state.computer.points + 1
: state.computer.points,
},
};
},
});
function Game() {
const player = useSelector(({ player }) => player);
const computer = useSelector(({ computer }) => computer);
const game_ready = useSelector(({ game_ready }) => game_ready);
const dispatch = useDispatch();
const history = useHistory();
const handleReset = React.useCallback(() => {
dispatch(distCards());
}, [dispatch]);
useEffect(() => {
if (game_ready) {
dispatch(distCards());
} else {
history.replace("/");
}
}, [game_ready]);
useEffect(() => {
if (player.current_card && computer.current_card) {
dispatch(pointsIncreament());
}
}, [player.current_card, computer.current_card]);
const handleClick = React.useCallback(() => {
dispatch(setNextCards());
});
return (
<div className="flex justify-center">
<div className="flex flex-col">
<div>
<div>{player.name}</div>
<div>Points: {player.points}</div>
<div>{player.current_card}</div>
</div>
<div>
<div>{computer.current_card}</div>
<div>Points: {computer.points}</div>
<div>{computer.name}</div>
</div>
{!player.cards.length || !computer.cards.length ? (
<Button
onClick={handleReset}
type="submit"
color="primary"
variant="contained"
>
Again?
</Button>
) : (
<Button
onClick={handleClick}
type="submit"
color="primary"
variant="contained"
>
next
</Button>
)}
<div>
{!player.cards.length || !computer.cards.length ? (
player.points === computer.points ? (
<h2>It's a tie</h2>
) : player.points > computer.points ? (
<h2>{player.name} won!</h2>
) : (
<h2>{computer.name} won!</h2>
)
) : (
""
)}
</div>
</div>
</div>
);
}
export default Game;

Resources