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

question-closed react, zmiana stanu działa jeżeli użyję operatora przypisania

Object Storage Arubacloud
0 głosów
196 wizyt
pytanie zadane 6 września 2020 w JavaScript przez rob Bywalec (2,440 p.)
zamknięte 10 września 2020 przez rob

Witam

Mam taki kod

  const [startDate, setStartDate] = useState(null);
    const [newTask, setNewTask] = useState(initTask)


    const handleChange = (e) => {
        if (e.target.id === 'newTask') {
            // newTask.title = e.target.value
            setNewTask({
                ...newTask, title: e.target.value
            })

dlaczego mi to nie działa? jeżeli odkomentuję 4 linijkę od końca a zakomentuję 3 ostatnie kod działa, ale nie powinno się zmieniać stanu poprzez operator przypisania

proszę o pomoc

komentarz zamknięcia: Znalazłem rozwiązanie
komentarz 6 września 2020 przez ScriptyChris Mędrzec (190,190 p.)
Po czym stwierdzasz, że nie działa?
komentarz 6 września 2020 przez rob Bywalec (2,440 p.)
Nie działa bo na ekranie jest puste miejsce, zamiast title, no i console.log() wskazuje że title jest dalej null
komentarz 6 września 2020 przez ScriptyChris Mędrzec (190,190 p.)

Czy initTask początkowo zawiera property title? Czy dopiero w momencie użycia setNewTask nowy stan będzie zawierał to property?

komentarz 6 września 2020 przez rob Bywalec (2,440 p.)

tak zawiera o wartości null, tu jest cały komponent

import React, { useState } from 'react'
import { connect } from 'react-redux'
import DatePicker from "react-datepicker"
import "react-datepicker/dist/react-datepicker.css"
import Popup from "reactjs-popup";
import Modal from './Modal'

function Add(props) {

    const initTask = {
        title: null,
        titleMarked: false,
        id: null,
        edit: false,
        flag: 'yellow',
        date: null,
        countDown: null,
        alarm: {
            setAlarm: null,
            isAlarm: false,
            iconOn: false
        },
        detail: [
            { point: null, pointMarked: false },
            { point: null, pointMarked: false },
            { point: null, pointMarked: false }
        ],
        notes: null,
    }

    const [startDate, setStartDate] = useState(null);
    const [newTask, setNewTask] = useState(initTask)
    console.log(newTask)

    const handleChange = (e) => {
        if (e.target.id === 'newTask') {
            // newTask.title = e.target.value.substring(0, 23)
            setNewTask({
                ...newTask, title: e.target.value
            })
        }
        if (e.target.id === 'pointOne') {
            setNewTask({
                ...newTask, detail: newTask.detail.map(each => {
                    if (each != newTask.detail[0]) return each; return { point: e.target.value, pointMarked: false }
                })
            })
        } if (e.target.id === 'pointTwo') {
            setNewTask({
                ...newTask, detail: newTask.detail.map(each => {
                    if (each != newTask.detail[1]) return each; return { point: e.target.value, pointMarked: false }
                })
            })
        } if (e.target.id === 'pointThree') {
            setNewTask({
                ...newTask, detail: newTask.detail.map(each => {
                    if (each != newTask.detail[2]) return each; return { point: e.target.value, pointMarked: false }
                })
            })
        } if (e.target.id === 'selectColor') { setNewTask({ ...newTask, flag: e.target.value }) }
        if (e.target.id === 'notes') {
            // setNewTask({ ...newTask, notes: e.target.value })
            newTask.notes = e.target.value
        }
        if (e.target.id === 'alarm') {
            // setNewTask({
            //     ...newTask, alarm: { setAlarm: e.target.value, isAlarm: false, iconOn: true }
            // })
            // newTask.alarm.setAlarm = null
            newTask.alarm.setAlarm = e.target.value
            newTask.alarm.iconOn = true
        }
        setNewTask({
            ...newTask, id: new Date().getTime()
        })

    }



    const handleSubmit = (e, id) => {
        e.preventDefault()
        console.log(newTask)
        newTask.date = startDate
        props.displayDetail(newTask.id)
        props.addNewTask(newTask)
        props.display('task')



    }
    const handleDate = (date) => {
        setStartDate(date)
    }
    const handleModal = () => { }

    return (
        <>
            <form className="add" onSubmit={handleSubmit} type='submit'>
                <input onChange={handleChange} id='newTask' type="text" />
                <label htmlFor="text">new task</label>
                <input onChange={handleChange} placeholder='optional' id='pointOne' type="text" />
                <label htmlFor="text">point one</label>
                <input onChange={handleChange} placeholder='optional' id='pointTwo' type="text" />
                <label htmlFor="text">point two</label>
                <input onChange={handleChange} placeholder='optional' id='pointThree' type="text" />
                <label htmlFor="text">point three</label>
                <select id='selectColor' onChange={handleChange}>
                    <option value="orange">Miscelanneus-orange</option>
                    <option value="green">Personal-green</option>
                    <option value="red">Urgent!-red</option>
                    <option value="blue">Work-blue</option>
                    <option value="purple">Family-purple</option>
                </select>

                <DatePicker
                    selected={startDate}
                    onChange={date => handleDate(date)}
                    timeInputLabel="Time:"
                    dateFormat="MM/dd/yyyy h:mm aa"
                    showTimeInput
                    placeholderText="Click to select a date"
                />
                <select id='alarm' onChange={handleChange}>
                    <option value={null}>---</option>
                    <option value={startDate}>todo time</option>
                    <option value={startDate - 60000}>half an hour before</option>
                    <option value={startDate - 120000}>an hour before</option>
                </select>
                <Modal handleModal={handleModal()} />
                <textarea className="add-textarea" onChange={handleChange} id="notes" name="notes" cols="35" rows="10"></textarea>
                <button>ADD</button>
            </form >
        </>
    )
}
const mapStateToProps = (state) => {
    return {
        add: state,
        position: state.position
    }
}
const mapDispatchToProps = (dispatch) => {
    return {
        addNewTask: (newTask) => { dispatch({ type: 'ADD_NEW_TASK', newTask: newTask }) },
        displayDetail: (id) => { dispatch({ type: 'DISPLAY_DETAIL', id: id }) },
        display: (id) => { dispatch({ type: 'DISPLAY', id: id }) },
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(Add)

 

komentarz 6 września 2020 przez ScriptyChris Mędrzec (190,190 p.)

A czy jeśli wymusisz rerender komponentu (np. wykonując jakąś akcję na widoku, która wymusza zmiany w komponencie) po tym jak wywoła się setNewTask, to czy stan newTask aktualizuje się?

komentarz 6 września 2020 przez rob Bywalec (2,440 p.)
rerender  to chyba cały czas się wykonuje bo ten console.log z 33 lini wyświetla się dwa razy na sekundę i on właśnie wyświetla newTask z property title:null
komentarz 6 września 2020 przez ScriptyChris Mędrzec (190,190 p.)

Hmm, console.log w 33 linii wywołuje się raz na jedną instancję komponentu Add, więc czy ten cały komponent jest wielokrotnie tworzony? Tobie chodzi o to, żeby dla każdej instancji tego komponentu wartość property title dla state-u newTask była inna?

komentarz 6 września 2020 przez rob Bywalec (2,440 p.)

Ha :) nie spojrzałem na to z tej strony, Nie wiem czy ten komponent jest tworzony tyle razy, nie było to moim zamiarem, może przez Datepicker? ten komponent ma za zadanie stworzenie nowego taska- czyli title na początek, podpunkty, kiedy jest deadline, czy ustawić alarm, ile wcześniej itd, wszystko ustawia się tylko raz

 

komentarz 6 września 2020 przez ScriptyChris Mędrzec (190,190 p.)

Czy Datepicker jest Twoim komponentem, czy to komponent z zewnętrznej biblioteki? Możesz pokazać w jaki sposób używasz komponentu Add za pośrednictwem komponentu Datepicker?

komentarz 6 września 2020 przez rob Bywalec (2,440 p.)

stąd mam datepicker

https://reactdatepicker.com/

jest on użyty w tym kodzie co Ci wysłałem na dole, myślisz, że to może być przez Datepicker?

komentarz 6 września 2020 przez ScriptyChris Mędrzec (190,190 p.)
edycja 6 września 2020 przez ScriptyChris

W kodzie komponent App Add zwraca funkcję renderującą, która używa DatePicker, a użycie App Add widać dopiero jako przekazanie parametru do funkcji zwróconej przez exportowany Reduxowy connect. Co dalej używa (importuje) komponentu App Add?

komentarz 6 września 2020 przez rob Bywalec (2,440 p.)
Chodzi o komponent Add ? Nie wiem czy dobrze rozumię, ale po kliknięciu w button ADD w komponecie Add następuje submit i zmienia się stan- wszystkie dane z form są przekazane do stanu więc Add nie jest już potrzebny i przestaje być renderowany- nic już go nie używa,  a pojawia się renderowany component Task z wszystkimi danymi które w cześniej zostały ustawione
komentarz 6 września 2020 przez ScriptyChris Mędrzec (190,190 p.)

Tak, miałem na myśli komponent Add (nie App) - przepraszam, poprawiłem.

Czegoś tu nie rozumiem. Skoro twierdzisz, że po zatwierdzeniu formularza komponent Add nie jest już potrzebny, to w jaki sposób console.log z 33 linijki wywołuje się po kilka razy? Wg mnie komponent Add jest użyty w więcej niż jednym miejscu (lub więcej niż raz).

A co pokazuje console.log z 83 linii (wewnątrz funkcji handleSubmit), gdy do inputa o id "newTask" wpiszesz cokolwiek i zatwierdzisz formularz bez dotykania innych pół? Czy wtedy stan newTask zawiera property title?

komentarz 6 września 2020 przez rob Bywalec (2,440 p.)
edycja 6 września 2020 przez rob

tak to wygląda live

https://robkot500.github.io/to_do/

jeżeli jest kliknięta zakładka add wyswietla się form i  console.log cały czas się wywołuje, a po kliknięciu button ADD następuje zatwierdzenie i wyświetlenie zakładki Task i console.log przestaje się wywoływać

console.log z 83 lini pokazuje title:null, jakby nie było wogóle zmiany stanu....

komentarz 6 września 2020 przez ScriptyChris Mędrzec (190,190 p.)

Funkcja App jest cyklicznie wołana w setInterval z komponentu countDown, dlatego w konsoli widać spam console.log-ów.

Nie wiem dlaczego aktualizacja state dla newTask nie uwzględnia property title, bo o dziwo property id (ustawiane na końcu funkcji handleChange) jest uwzględniane.

Sprawdziłem w debuggerze i nawet użycie setNewTask z funkcją aktualizującą stan nie pomaga, więc nie wiem o co chodzi. Może to kwestia specyficznego użycia setInterval z Reduxem, albo jakiś corner case lub niezrozumienie Reacta.


Sprawdzałeś, czy aktualizacja state-u newTask w pozostałych ifach działa - tzn. czy wypełniając pozostałe pola formularza, to jest brane pod uwagę w state?

komentarz 6 września 2020 przez rob Bywalec (2,440 p.)

i tu jest cała zagwózdka bo

wszystkie trzy point, flag i id działają stan się zmienia a

title, notes, alarm.setAlarm i alarm.iconOn nie działają 

i wszystkie są w tym samym handleChange !!!! skąd taka wybiórczość?! frown

komentarz 6 września 2020 przez ScriptyChris Mędrzec (190,190 p.)

Szczerze mówiąc nie wiem. Próbując modyfikować kod przez debugger, zauważyłem że dowolna inna zmiana w pliku App.js nie powoduje efektu, bo to zmiany na source mapie, a oryginalny kod pozostaje bez zmian.

Spróbuj aktualizować stan przez callback, na zasadzie:

setNewTask((previousState) => ({
  ...previousState, title: e.target.value
}));

Jeśli to nie pomoże, to nie wiem o co chodzi. Niemniej, odświeżanie całego komponentu w setInterval może nie być dobrym pomysłem. Raczej powinno się odświeżać określone wartości, np. licznik lub czas (jeśli to zegarek).

komentarz 6 września 2020 przez rob Bywalec (2,440 p.)
w każdym razie bardzo dzięki za poświęcony czas
komentarz 10 września 2020 przez rob Bywalec (2,440 p.)

wiem w czym problem!!! 

wystarczyło przenieść tę linijkę

setNewTask({
            ...newTask, id: new Date().getTime()
        })

w miejsce gdzie będzie uruchamiana tylko raz ponieważ, wcześniej była wywoływana bezwarunkowo za każdym wywołaniem handleChnage i to wszystko mieszało...

Podobne pytania

0 głosów
1 odpowiedź 284 wizyt
pytanie zadane 29 stycznia 2021 w JavaScript przez sKodowany Obywatel (1,150 p.)
0 głosów
0 odpowiedzi 86 wizyt
pytanie zadane 2 sierpnia 2020 w JavaScript przez rob Bywalec (2,440 p.)
+1 głos
1 odpowiedź 366 wizyt

92,624 zapytań

141,482 odpowiedzi

319,822 komentarzy

62,005 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!

...