Значение объекта всегда отображается как «неопределенное» в React. - PullRequest
0 голосов
/ 13 апреля 2020

У меня проблема с тем, что я не могу получить доступ к значению объекта, возможно, потому что DOM визуализируется до того, как программа извлекает данные и помещает их в объект.

Я пытаюсь реализовать страницу, на которой вы видите все отзывы всех пользователей. На странице вы также можете увидеть, какой отзыв вам уже понравился или нет. Чтобы достичь этого, я хочу получить доступ ко всем лайкам, которые есть у пользователя.

Это начальное состояние объекта.

const initialState = {
    likes: {},
};

И этот объект будет заполнен данные извлекаются с сервера API следующим образом:

likes = {
    1: {id: 38, user_id: 3, review_id: 1, created_at: "2020-04-11T04:12:14.569Z", updated_at: "2020-04-11T04:12:14.569Z"}
    2: {id: 24, user_id: 3, review_id: 2, created_at: "2020-04-11T03:25:16.589Z", updated_at: "2020-04-11T03:25:16.589Z"}
    3: {id: 20, user_id: 3, review_id: 3, created_at: "2020-04-09T12:07:34.669Z", updated_at: "2020-04-09T12:07:34.669Z"}
}

Ниже приведен компонент, представляющий некоторую информацию о проверке, такую ​​как заголовок, имя пользователя, количество похожих отсчетов и т. д. c. информация унаследована от родительского компонента с помощью prop "review".

<ReviewCard.js> 
const ReviewCard = props => {
    let { id, user_id, title, image, rate, good, likes_count, gameId, createdAt } = props.review;
    const userId = useSelector(state => state.authReducer.userId);
    .
    .
    .
    let favorite = <LikeButton 
                        likesCount={likes_count}
                        userId={userId} 
                        reviewId={id}
                    />

return (
        <Card className={classes.root}>
            <CardHeader
                .
                .
                .
                action={favorite}
                title={title}
                subheader={createdAt}
            />
    .
    .
    . 
);

Компонент LikeButton буквально является кнопкой like. Я хочу изменить цвет кнопки в зависимости от того, понравился ли пользователю обзор или нет. Тем не менее, if (likes[reviewId]) всегда игнорируется, поскольку likes[reviewId] равен undefined даже после заполнения объекта likes фактическими данными, извлеченными из API.

<LikeButton.js>
const LikeButton = props => {
    let { likesCount, userId, reviewId } = props;
    const dispatch = useDispatch();
    const likes = useSelector(state => state.likeReducer.likes);

    const [count, setCount] = useState(likesCount);

    useEffect(() => {
        dispatch(actions.fetchLike(likes, userId, reviewId));
    }, [props, likes, count]);

    .
    .
    .

    console.log('likes is ', likes);
    console.log('reviewId is', reviewId);
    console.log(`like with reviewId = ${reviewId} is `, likes[reviewId]);

    let favorite = (
        <div className={classes.LikeButton}>
            <FavoriteBorderIcon 
                onClick={onLikeHandler}
                className={classes.Icon}
            />
            {count}
        </div>
    );

    if (likes[reviewId]) {
        favorite = (
            <div className={classes.LikeButton}>
                <FavoriteIcon 
                    onClick={onUnlikeHandler}
                    className={classes.FavoriteIcon}
                />
                {count}
            </div>
        );
    }

    return (
        <div>
            {favorite}
        </div>
    );
};

Ниже приведено аналогичное действие для Redux.

<./actions/like.js>
export const setLike = likes => {
    return {
        type: actionTypes.SET_LIKE,
        likes: likes,
    };
};

export const fetchLike = (likes, userId, reviewId) => {
    return dispatch => {
        const url = `http://localhost:3001/users/${userId}/reviews/${reviewId}/likes/1`;
        axios
            .get(url)
            .then(response => {
                likes[reviewId] = response.data; 
                dispatch(setLike(likes));
            })
            .catch(error => {
                console.log(error);
            });
    }
};

Ниже приведен аналогичный редуктору для Redux.

<./reducer/like.js>
const initialState = {
    likes: {},
};

const setLike = (state, action) => {
    return updateObject(state, {
        likes: action.likes,
    });
};

const reducer = (state = initialState, action) => {
    switch (action.type) {
        case actionTypes.SET_LIKE:
            return setLike(state, action);
        default:
            return state;
    }
};

Как только fetchLike извлекает likes пользователя, он сохраняется в likes: {}. На самом деле, console.log('likes is ', likes); в LikeButton. js показывает содержимое likes после завершения fetchLike(). Тем не менее, console.log(, как и для reviewId = $ {reviewId}, равно , likes[reviewId]);, по-прежнему отображается undefined. Изображение: Результаты console.log () ;

Я предполагаю, что может быть некоторая проблема с синхронизацией, когда он выбирает данные и страница отображается. (Я знаю, useEffect срабатывает каждый раз, когда меняются переменные во втором параметре ...)

Буду признателен, если вы дадите несколько советов по этому поводу.

Спасибо за чтение :)

Ответы [ 2 ]

0 голосов
/ 13 апреля 2020

Используйте экран загрузки с оператором if else.

if (лайки) "Загружается ...": не загружается et c ...

0 голосов
/ 13 апреля 2020

Причина в том, что ваш ax ios вызов отвечает асинхронно , поэтому ваше состояние likes будет обновлено чуть позже. Вероятно, вы можете фиксировать изменения с помощью useEffect() hook.

Попробуйте сделать следующее:

useEffect(() => {
   console.log('likes is ', likes);
}, [likes]);

После этого ваш likes войдет в консоль. как только это изменит состояние.

Надеюсь, это поможет!

...