• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Edytowanie listy w aplikacji przy pomocy AppContext - react

Object Storage Arubacloud
0 głosów
213 wizyt
pytanie zadane 5 lipca 2021 w JavaScript przez ShockWave Bywalec (2,350 p.)

Cześć, 

mam pytanie ponieważ mam problem podczas tworzenia aplikacji. Chciałbym edytować pojedynczą listę w aplikacji budżetowej,

ale nie mam pojęcia w jaki sposób mogę to zrobić i potrzebuje wskazówki.

// ExpenseItem

import React, { useContext } from 'react';
import { TiDelete } from 'react-icons/ti';
import { TiPencil } from 'react-icons/ti';
import { AppContext } from '../context/AppContext';


const ExpenseItem = (props) => {

    const { dispatch } = useContext(AppContext);

    const handleDeleteExpense = () => {
        dispatch({
            type: 'DELETE_EXPENSE',
            payload: props.id,
        })
    }

    const handleEditExpense = () => {
        dispatch({
            type: 'EDIT_EXPENSE',
            payload: props.id,
        })
    }

    return (
        <li className='list-group-item d-flex justify-content-between align-items-center mt-4 me-4'>
            {props.name}
            <div>
                <span className='badge bg-primary badge-pill me-4'>
                    ${props.cost}
                </span>
                <TiPencil className='me-2' size='1.5em' onClick={handleEditExpense}></TiPencil>
                <TiDelete size='1.5em' onClick={handleDeleteExpense}></TiDelete>
            </div>
        </li>
    )
};

export default ExpenseItem;

// AppContext

import { createContext, useReducer } from "react";

const AppReducer = (state, action) => {
    switch(action.type){
        case 'ADD_EXPENSE':
            return {
                ...state,
                expenses: [...state.expenses, action.payload],
            }
        case 'ADD_INCOME':
            return {
                ...state,
                incomes: [...state.incomes, action.payload],
            }
        case 'DELETE_EXPENSE':
            return {
                ...state,
                expenses: state.expenses.filter((expense) => expense.id !== action.payload)
            }
        case 'DELETE_INCOME':
            return {
                ...state,
                incomes: state.incomes.filter((incomes) => incomes.id !== action.payload)
            }
        case 'EDIT_EXPENSE':
            return {
                
            }
        default:
            return state;
    }
}

const initailState = {
    budget: 0,
    expenses: [
        // { id: 2, name: 'shopping', cost: 40 },
    ],
    incomes: [

    ],
};

export const AppContext = createContext();

export const AppProvider = (props) => {
    const [state, dispatch] = useReducer(AppReducer, initailState);
    
    return (
        <AppContext.Provider value={{
            budget: state.budget,
            expenses: state.expenses,
            incomes: state.incomes,
            dispatch,
        }}
    >
        {props.children}
    </AppContext.Provider>)
}

Jeśli ktoś będzie chciał to podam również link do repozytorium.

Z góry dziękuję za pomoc.

1 odpowiedź

0 głosów
odpowiedź 6 lipca 2021 przez ScriptyChris Mędrzec (190,190 p.)

Zakładam, że chodzi Ci o nieuzupełniony case 'EDIT_EXPENSE'. Chcąc edytować któryś element w tablicy - albo raczej podmienić jego wartość w nowym stanie, żeby go nie mutować - przekaż indeks tego elementu i odnieś się do niego po indeksie, albo użyj metody Array.prototype.findIndex, aby go znaleźć jego indeks po konkretnym propertisie (widzę, że w komponencie masz props.id, więc można skorzystać z tego). Potem wstaw w jego miejsce nowy obiekt. Albo wyfiltruj stary obiekt expense i w jego miejsce wstaw nowy (lub dopushuj na koniec tablicy).

Po funkcji handleEditExpense i parametrze props.id przekazywanym do dispatchera sądzę, że możesz zrobić coś w tym stylu:

const handleExitExpense = () => {
    dispatch({
        type: 'EDIT_EXPENSE',
        payload: {
             id: props.id,
             expenseToEdit: {} // <- tutaj przekaż nowe wartości dla edytowanego expense
        }
    })
}

// w AppReducer 

case 'EDIT_EXPENSE':
  const expenseIndexToEdit = 
      state.expenses.findIndex((expense) => expense.id === action.payload.id);
  const editedExpenses = /* kopiowanie state.expenses i zastąpienie w kopii edytowanego elementu expense */
      [...state.expenses].splice(expenseIndexToEdit, 1, action.payload.expenseToEdit);

  // alternatywnie można użyć `.filter()` by wyrzucić stary expense i potem dodać nowy

  return {
      ...state,
      expenses: editedExpenses
  }

 

komentarz 14 lipca 2021 przez ScriptyChris Mędrzec (190,190 p.)

Uncaught Error: input is a void element tag and must neither have `children` nor use `dangerouslySetInnerHTML`

Elementy <input> są - jak wskazuje błąd - puste w środku.

Więc zapisy w stylu:

<input onChange={EditCost()} value={props.cost}>{props.cost}</input>

, zamień na:

<input onChange={EditCost()} value={props.cost} />
komentarz 14 lipca 2021 przez ShockWave Bywalec (2,350 p.)

Wyświetla ten input, tylko teraz mam problem z tym, żeby edytować wartość tego inputu. Przy próbie wpisania wartości wyświetla cały czas "ww" i "22"

komentarz 14 lipca 2021 przez ScriptyChris Mędrzec (190,190 p.)

Tutaj dobrze będzie skopiować na starcie propsy (przekazywane do value) do zmiennych stanowych komponentu i aktualizować je w handlerze onChange.

Swoją drogą, radziłem Ci, abyś pozbył się nawiasów przy przekazywaniu funkcji do onChange handlera, ale w komentarzu wyżej przeoczyłem, że jeszcze tego nie zrobiłeś, więc moja propozycja błędnie te nawiasy zawiera.

komentarz 14 lipca 2021 przez ShockWave Bywalec (2,350 p.)
W kodzie mam bez nawiasów. Nie bardzo wiem jak aktualizować stan, ponieważ pierwszy raz używam tego API Context, zaraz coś pomyślę i jak na nic nie wpadnę to dam znać.
komentarz 14 lipca 2021 przez ShockWave Bywalec (2,350 p.)
import { createContext, useReducer } from "react";

const AppReducer = (state, action) => {
    switch(action.type){
        case 'ADD_EXPENSE':
            return {
                ...state,
                expenses: [...state.expenses, action.payload],
            }
        case 'ADD_INCOME':
            return {
                ...state,
                incomes: [...state.incomes, action.payload],
            }
        case 'DELETE_EXPENSE':
            return {
                ...state,
                expenses: state.expenses.filter((expense) => expense.id !== action.payload)
            }
        case 'DELETE_INCOME':
            return {
                ...state,
                incomes: state.incomes.filter((incomes) => incomes.id !== action.payload)
            }
        case 'EDIT_EXPENSE':
            const expenseIndexToEdit = 
            state.expenses.findIndex((expense) => expense.id === action.payload.id);
            const editedExpenses = /* kopiowanie state.expenses i zastąpienie w kopii edytowanego elementu expense */
                [...state.expenses].splice(expenseIndexToEdit, 1, action.payload.expenseToEdit);
            return {
                ...state,
                expenses: editedExpenses
            }
        default:
            return state;
    }
}

const initailState = {
    budget: 0,
    expenses: [
        // { id: 2, name: 'shopping', cost: 40 },
    ],
    incomes: [

    ],
};

export const AppContext = createContext();

export const AppProvider = (props) => {
    const [state, dispatch] = useReducer(AppReducer, initailState);
    
    return (
        <AppContext.Provider value={{
            budget: state.budget,
            expenses: state.expenses,
            incomes: state.incomes,
            dispatch,
        }}
    >
        {props.children}
    </AppContext.Provider>)
}

Muszę się jakoś odnieść do context? do expenses: state.expenses?

Podobne pytania

0 głosów
1 odpowiedź 234 wizyt
pytanie zadane 6 grudnia 2022 w JavaScript przez DzikieHarce Użytkownik (690 p.)
+1 głos
3 odpowiedzi 665 wizyt
pytanie zadane 3 maja 2021 w JavaScript przez rszczepanski02 Obywatel (1,180 p.)
+1 głos
0 odpowiedzi 180 wizyt
pytanie zadane 10 września 2020 w JavaScript przez creend Gaduła (4,700 p.)

92,568 zapytań

141,421 odpowiedzi

319,627 komentarzy

61,956 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...