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

React useEffect renderowanie

VPS Starter Arubacloud
0 głosów
263 wizyt
pytanie zadane 19 stycznia 2022 w JavaScript przez gunaterek Bywalec (2,760 p.)
const NotePage = ({match, load_note,delete_note, update_note, create_note, note, isAuthenticated, history, user}) => {
    const noteId = match.params.id
    const [noteT, setNoteT] = useState({
        body:'',
        headline:'',
        user_id: user
    })
    useEffect(() => {
        getNote()
    }, [noteId])


    const getNote = async () => {
        if (noteId === 'new') return
        load_note(noteId)
        setNoteT(note)
    }

    if (!isAuthenticated){
        return <Redirect to='/login'/>
      }

    const handleChange = (e) => {
        setNoteT(noteT => ({ ...noteT, [e.target.name]: e.target.value }))
    }
    const deleteNote = async () => {
        delete_note(noteId)
        history.push('/')
    }
    const handleSubmit = () => {
        if (noteId !== 'new' && noteT.body === '') {
            delete_note(noteId)
        }else if(noteId !== 'new') {
            console.log('update')
            update_note(noteId, noteT)
        }else if (noteId === 'new') {
            setNoteT(noteT => ({...noteT, user_id: user}))
            create_note(noteT)
        }
        history.push('/')
    }
    return(
        <React.Fragment>
            <div class = 'flex-none'>
                <NoteNavBar/>
            </div>
            <div class='flex-1 py-2 grid justify-items-center'>
                <textarea class='font-bold text-lg my-2 w-4/5 text-center text-gray-300 bg-gray-600' name='headline' onChange={(e) => { handleChange(e) }} value={noteT?.headline} ></textarea>
                <textarea class='my-2 w-4/5 h-64 text-gray-300 bg-gray-600' name='body' onChange={(e) => { handleChange(e) }} value={noteT?.body}></textarea>
            </div>

            <div class=" flex justify-between">
            <button onClick={deleteNote} class="font-bold border-2 rounded-md border-opacity-70 border-red-400 text-red-400 text-center px-2">Delete</button>
            <button onClick={handleSubmit} >    
                <img  src={Add} class='h-16' alt="fireSpot"/>
            </button>
            </div>
        </React.Fragment> 
    );
  };
  const mapStateToProps = state => ({
    note: state.notes.note,
    isAuthenticated: state.auth.isAuthenticated,
    user: state.auth.user.id,
  });
  export default connect(mapStateToProps, {create_note, load_note, delete_note, update_note})(NotePage);

Witam, szukam rozwiązania problemu. Obecny widok odpowiada za pokazanie w zależnosci od ID w linku który komponent ma pobrać z bazy i go wyświetlić. Problem w tym, że useEffect wywołuje się po wyrenderowaniu wszystkiego co za tym idzie noteT przypisywane jest z bazy po renderze i renderując ponownie z innym komponentem widoczny jest poprzedni. Funkcja w UseEffect zapisuje do stanu note potrzebny aktualnie komponent.
Czy ktoś wie jak mogę to rozwiązać ?. Działać działa :D tylko trzeba dwa razy wejść żeby się wyświetlił poprawny :D 

komentarz 19 stycznia 2022 przez ScriptyChris Mędrzec (190,190 p.)

Możesz pokazać implementację funkcji load_note?

komentarz 19 stycznia 2022 przez gunaterek Bywalec (2,760 p.)
export const load_note = (noteId) => async dispatch => {
    if (localStorage.getItem('access') && noteId !== 'new') {
        const config = {
            headers: {
                'Content-Type': 'application/json'
            }
        }; 
        config.headers.Authorization = 'JWT ' + localStorage.getItem('access');
        try {
            const res = await axios.get(`${process.env.REACT_APP_API_URL}/note/${noteId}/`, config)
            dispatch({
                type: LOAD_NOTE_SUCCESS,
                payload: res.data
            });
        } catch (err) {
            dispatch({
                type: LOAD_NOTE_FAIL
            });
        }

    } else {
        dispatch({
            type: LOAD_NOTE_FAIL
        });
    }
};

i prosty case jeśli SUCCESS

 

        case LOAD_NOTE_SUCCESS:
            return {
                ...state,
                note: payload,
    
            }

 

komentarz 19 stycznia 2022 przez ScriptyChris Mędrzec (190,190 p.)

Skoro load_note zwraca funkcję asynchroniczną, która przyjmuje callback dispatch, to dlaczego nie obsługujesz tego tutaj?
 

const getNote = async () => {
        if (noteId === 'new') return
        load_note(noteId)
        setNoteT(note)
    }
komentarz 19 stycznia 2022 przez gunaterek Bywalec (2,760 p.)
chodzi o useReducer ? Jestem totalnie zielony
komentarz 19 stycznia 2022 przez ScriptyChris Mędrzec (190,190 p.)
Możesz udostępnić działające demo na sandboxie, np. https://codesandbox.io/ ?
komentarz 19 stycznia 2022 przez gunaterek Bywalec (2,760 p.)
edycja 19 stycznia 2022 przez gunaterek

https://codesandbox.io/s/frosty-shaw-n60wc? cieżko żeby działało ale wszystkie potrzebne pliki wrzuciłem. Nie będę ukrywał, że jest to tworzone na potrzeby projektu i rozwiązania są z gotowych implementacji 

komentarz 19 stycznia 2022 przez ScriptyChris Mędrzec (190,190 p.)

Przydało by się, żeby dało się to uruchomić, żeby móc zdebugować problem.

W każdym razie, na oko nie bardzo rozumiem sensu funkcji getNote, bo ona korzysta z load_note, ale nic nie robi z jej zwróconą wartością, po czym ustawia nowy stan dla noteT na podstawie parametru otrzymanego z property note (który trafia do całego komponentu NotePage). Podejrzewam, że równie dobrze mógłbyś taki stan ustawić już na początku, czyli zamiast:

const [noteT, setNoteT] = useState({
    body:'',
    headline:'',
    user_id: user
})

zapisać:

const [noteT, setNoteT] = useState(note)

 

komentarz 19 stycznia 2022 przez gunaterek Bywalec (2,760 p.)

Już wiem w czym problem ... 

    useEffect(() => {
        if (noteId === 'new') return
        load_note(noteId)
        setNoteT(note)
    }, [noteId])

setNoteT nie czeka na load_note i używa poprzedniego stanu. Jeszcze nie wiem jak zrobić aby najpierw do końca wykonało load_note i pozniej setNoteT. Pewnie chodzi o async

1 odpowiedź

0 głosów
odpowiedź 19 stycznia 2022 przez ScriptyChris Mędrzec (190,190 p.)

setNoteT nie czeka na load_note i używa poprzedniego stanu. Jeszcze nie wiem jak zrobić aby najpierw do końca wykonało load_note i pozniej setNoteT. Pewnie chodzi o async

Tak, jeśli load_note wykonuje kod asynchronicznie - a na pewno zwraca funkcję asynchroniczną (choć nie wiem, co ją woła) - to powinieneś użyć na tym await lub podpiąć się pod then:

useEffect(() => {
    if (noteId === 'new') return
    load_note(noteId).then(() => setNoteT(note));
}, [noteId])

// albo
useEffect(() => {
    (async () => { // osobna funkcja wewnątrz callbacka do useEffect, bo inaczej React będzie miał z tym problem
        if (noteId === 'new') return
        await load_note(noteId);
        setNoteT(note);
    })();
}, [noteId])

Co do (nie) użycia async bezpośrednio na callbacku przekazywanym do useEffecthttps://dev.to/danialdezfouli/what-s-wrong-with-the-async-function-in-useeffect-4jne

Podobne pytania

+1 głos
1 odpowiedź 150 wizyt
pytanie zadane 27 maja 2021 w JavaScript przez p4wix Obywatel (1,040 p.)
+1 głos
1 odpowiedź 303 wizyt
pytanie zadane 31 stycznia 2022 w JavaScript przez Oskar Szkurłat Bywalec (2,780 p.)
0 głosów
1 odpowiedź 233 wizyt
pytanie zadane 29 grudnia 2020 w JavaScript przez sKodowany Obywatel (1,150 p.)

92,455 zapytań

141,263 odpowiedzi

319,099 komentarzy

61,854 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

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 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!

...