Путаница с перехватом реакции

#reactjs #react-hooks

#reactjs #реагирующие крючки

Вопрос:

Я запутался с крючками useEffect и useState. У меня есть страница, на которой я загружаю список фильмов, используя перехват useEffect. Список хорошо отображается на моем экране. Когда я хочу отредактировать фильм, я нажимаю на него, и это отправляет идентификатор этого фильма в метод, в котором я хочу найти фильм в списке фильмов в состоянии, загрузить этот фильм в форме и представить его для редактирования. Теперь, когда я хочу просмотреть этот фильм, список фильмов в моем состоянии пуст. Хотя это показано на моем экране. Итак, мне интересно, что тогда делают setMovies и как они отображаются на экране, но я получаю пустой массив где-либо еще?

Раньше я работал с компонентами класса, где это не было проблемой.

 import React, { useState, useEffect } from 'react';

const MovieList = () => {
    const [openEdit, setOpenEdit] = useState(false);
    const [movieToEdit, setMovieToEdit] = useState({});
    const [movies, setMovies] = useState([]);

    const openEditMovie = (movieId) => {
        console.log("movies", movies); // is empty here !?
        setMovieToEdit(movies.find(m => m.id === movieId));
        setOpenEdit(true);
    }

    useEffect(() => {
        fetchMovies();
    }, []);

    const fetchMovies = async () => {
        let movies = await axios.get('/movies'); // just sample code, you get the picture
        console.log("movies", movies); // lists movies
        setMovies(movies);
    }

    return (
        <List source={movies}/>
        { /* and the dialog with the form etc go below here */ }
    );
};

export default MovieList;
  

Комментарии:

1. Я сомневаюсь в именах переменных, можете ли вы изменить переменную movie на что-то другое?

2. Может быть, стоит прочитать -> reactjs.org/docs/hooks-reference.html amp; reactjs.org/docs/hooks-intro.html

3. @danialdehvan Мне трудно найти вызываемую переменную movie ..

Ответ №1:

Вот небольшой макет вашего кода, который, похоже, делает то, что ожидалось, поэтому я бы проверил возвращаемое значение вашего axios-вызова. Можете ли вы уточнить, отображается ли ваш журнал в функции [object Object] fetchMovie? Я спрашиваю, поскольку вы упомянули, что на самом деле в нем перечислены фильмы..

 import React, { useState, useEffect} from 'react';

const MovieList = () => {
    const [openEdit, setOpenEdit] = useState(false);
    const [movieToEdit, setMovieToEdit] = useState({});
    const [movies, setMovies] = useState([]);

    const openEditMovie = (movieId) => {
        console.log("movieLogEdit:",movies); // not empty
        setMovieToEdit(movies.find(m => m.id === movieId));
        setOpenEdit(true);
    }

    useEffect(() => {
        fetchMovies();
    }, []);

    const fetchMovies = async () => {
        let movies = [1,2,4]; // mocked data
        console.log("movieLogFetch:"   movies); // lists movies on initial render since useEffect has [] as second argument
        setMovies(movies);
    }

    return (
      <div>
        <button className="button is-primary" onClick={openEditMovie}>
          Open Movie Editor
        </button>
      </div>
    );
};

export default MovieList;
  

Ответ №2:

Ваш код кажется прекрасным. Просто измените setMovies(movies) на setMovies(movies.data) , потому что Axios возвращает объект ответа со свойством data , которое содержит данные, отправленные сервером (API).

 const fetchMovies = async () => {
  let movies = await axios.get("/movies");
  console.log("movies", movies.data);
  setMovies(movies.data);
};
  

Комментарии:

1. Спасибо за комментарий. Я понимаю вашу точку зрения, но вызов axios был просто псевдокодом. Однако я дважды проверю возвращаемое значение.

Ответ №3:

Ответ был найден, и я понимаю, что, упростив свой код, я упустил ту часть, которая вызвала проблему. В этом fetchMovies методе я создавал массив значений для передачи в таблицу данных пользовательского интерфейса Material (https://www.material-ui-datatables.com ).

 const fetchMovies = async () => {
    let movies = await axios.get('/movies'); // just sample code, you get the picture
    console.log("movies", movies); // lists movies
    setMovies(
        movies.map(movie => [
            movie.id, 
            movie.name, 
            movie.year, 
            <EditIcon onClick={() => openEditMovie(movie.id)}/>
        ])
    );
}
  

Теперь, по-видимому, как мне сказали, во время создания этого массива openEditMovie функция копируется в память вместе с состоянием, каким оно было в тот момент. Поэтому при вызове метода из onClick , у меня всегда будет доступно старое состояние с пустым массивом movies.
Когда вы позже вызываете openEditMovie где-то еще из кода, у меня есть доступ к обновленному состоянию.
Никогда не видел, что это произойдет!