Как я могу обновить свои реакции, когда я нажимаю любой значок

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

константы.js

/** @constant */
export const INITIAL_STATE = {
    uploads: new Map(),
};

export const USER_UPLOADS = [
    {
        _id: 0,      
        image: 'http://sugarweddings.com/files/styles/width-640/public/1.%20The%20Full%20Ankara%20Ball%20Wedding%20Gown%[email protected]',
        reactions: {
            dislike: 0,
            like: 0,
            maybe: 0,
        },
        story: "It's my birthday next week! What do you think?",
        user: 'Chioma',
    },
    {
        _id: 1,        
        image: 'https://dailymedia.com.ng/wp-content/uploads/2018/10/7915550_img20181007141132_jpeg01c125e1588ffeee95a6f121c35cd378-1.jpg',
        reactions: {
            dislike: 0,
            like: 0,
            maybe: 0,
        },
        story: 'Going for an event. Do you like my outfit?',
        user: 'Simpcy',
    },
    {
        _id: 2,        
        image: 'https://i0.wp.com/www.od9jastyles.com/wp-content/uploads/2018/01/ankara-styles-ankara-styles-gown-ankara-tops-ankara-gowns-ankara-styles-pictures-latest-ankara-style-2018-latest-ankara-styles-ankara-ankara-styles.png?fit=437%2C544&ssl=1',
        reactions: {
            dislike: 0,
            like: 0,
            maybe: 0,
        },
        story: 'Saturdays are for weddings. Yay or nay?',
        user: 'Angela',
    },
];

действия.js

import { UPDATE_REACTION, REQUEST_UPLOAD_LIST } from './actionTypes';

/**
 * Triggers request to react on a post
 *
 * @function
 * @return {Object} The {@link actionTypes.REQUEST_UPLOAD_LIST REQUEST_UPLOAD_LIST}
 * action.
 */
export function updateReaction(itemid, reaction) {
    return {
        itemid,
        reaction,
        type: UPDATE_REACTION,
    };
}

/**
 * Triggers request for the lists of uploads
 *
 * @function
 * @return {Object} The {@link actionTypes.REQUEST_UPLOAD_LIST REQUEST_UPLOAD_LIST}
 * action.
 */
export const requestUploadList = payload => ({
    payload,
    type: REQUEST_UPLOAD_LIST,
});

редукторы.js

import { UPDATE_REACTION, REQUEST_UPLOAD_LIST } from './actionTypes';
import { INITIAL_STATE, USER_UPLOADS } from './constants';

/**
 * Creates a Javascript Map with the user uploads mapped by id
 *
 * @param {Array} USER_UPLOADS - a users uploads
 * @return {Map} - the user uploads
 */

function generateUploadsMap() {
    const setOfUserUploads = new Map();

    USER_UPLOADS.forEach(userUpload => {
        const { _id } = userUpload;

        setOfUserUploads.set(_id, userUpload);
    });

    return setOfUserUploads;
}

function updateItemReactions(itemid, reaction, uploads) {
    const upload = uploads.get(itemid);
    upload.reactions = {
        ...upload.reactions,
        [reaction]: upload.reactions[reaction] + 1,
    };
    uploads.set(itemid, upload);
    return uploads;
}

console.info(updateItemReactions());
export default (state = { ...INITIAL_STATE }, action) => {
    switch (action.type) {
        case REQUEST_UPLOAD_LIST: {
            return {
                ...state,
                uploads: generateUploadsMap(),
            };
        }
        case UPDATE_REACTION: {
            const { uploads } = state;

            return {
                ...state,
                uploads: updateItemReactions(action.itemid, action.reaction, uploads),
            };
        }

        default:
            return state;
    }
};


home.js

import PropTypes from 'prop-types';
import React from 'react';
import { Avatar, Card, Icon, List } from 'antd';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

import { LIST_TEXTS, STYLES } from '../constants';
import * as actions from '../actions';
import { getUploads } from '../selectors';

const { AVATAR, CARD_CONTAINER, CARD_LIST, ICON, USER_LIST } = STYLES;
const { INNER, MORE, UPLOAD, VERTICAL } = LIST_TEXTS;

const IconText = ({ type, text }) => (
    <span>
        <Icon type = {type} style = {ICON} />
        {text}
    </span>
);
function createReactionsIcon(item, updateReaction) {
    const { like, dislike, maybe } = item.reactions;
    const icons = [
        { reaction: 'like', text: `${like}`, type: 'heart' },
        { reaction: 'dislike', text: `${dislike}`, type: 'dislike' },
        { reaction: 'maybe', text: `${maybe}`, type: 'meh' },
    ];
    return icons.map(({ reaction, text, type }) => (
        <IconText
          onClick = {updateReaction(item._id, reaction)}
          key = {reaction}
          type = {type}
          text = {text}
        />
    ));
}

class Home extends React.Component {
    componentDidMount() {
        const { requestUploadList } = this.props.actions;

        requestUploadList();

    }

        updateReaction = (itemid, reaction) => {
        const { updateReaction } = this.props.actions;
        updateReaction(itemid, reaction);
    }

    render() {
        const { uploads } = this.props;
        const values = Array.from(uploads.values());

        return (
            <div style = {CARD_CONTAINER}>
                <List
                  itemLayout = {VERTICAL}
                  dataSource = {values}
                  renderItem = {item => (
                      <List.Item style = {USER_LIST}>
                          <Card
                            actions = {createReactionsIcon(item, this.updateReaction)}
                            cover = {<img alt = {UPLOAD} src = {item.image} />}
                            extra = {<Icon type = {MORE} />}
                            hoverable
                            title = {(
                                <a href = "/">
                                    <Avatar src = {item.image} style = {AVATAR} />
                                    {item.user}
                                </a>
                            )}
                            type = {INNER}
                            style = {CARD_LIST}
                          >
                              {item.story}
                          </Card>
                      </List.Item>
                  )}
                />
            </div>
        );
    }
}

Home.propTypes = {
    uploads: PropTypes.instanceOf(Map),
    actions: PropTypes.object,
};

const mapStateToProps = state => ({
    uploads: getUploads(state),
});

const mapDispatchToProps = dispatch => ({
    actions: bindActionCreators(actions, dispatch),
});

export default connect(mapStateToProps, mapDispatchToProps)(Home);
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
0
42
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В mapDispatchToProps вы связали своих создателей действий и установили для реквизита actions, переданного в компоненте Home.

Элемент Icon, сгенерированный в createReactionsIcon, не знает способа обработки события onClick, если он не дает возможности отправить действие в redux-store, чтобы обновить реакцию на него.

В Homeactions.updateReactions нужно перенаправить на createReactionsIcon и зарегистрировать на событие onClick для своего IconText.


render() {
  //...
  <Card
    actions = {createReactionsIcon(item, this.props.actions.updateReaction)}
  //...
}

В createReactionsIcon,



function createReactionsIcon(item, updateReaction) {
  const { like, dislike, maybe } = item.reactions;


  const icons = [
    { reaction: 'like', text: `${like}`, type: 'heart'},
    { reaction: 'dislike', text: `${dislike}`, type: 'dislike'},
    { reaction: 'maybe', text: `${maybe}`, type: 'meh'},
  ];
  //...
  return icons.map(({ reaction, text, type }) => (
    <IconText 
      onClick = {() => updateReaction(item._id, reaction)} 
      key = {reaction}
      type = {type}
      text = {text}
    />
  ));
}

Здесь определение updateReaction создателя действия в actions.js должно быть изменено, чтобы включить больше полей, таких как элементы и реакция на действие.

function updateReaction(itemid, reaction) {
  return {
    type: UPDATE_REACTION,
    itemid,
    reaction
  }
}

Затем редуктор для типа действия UPDATE_REACTION используется для обновления реакции на идентификатор элемента в reducer.js.

///...
case UPDATE_REACTION:
  const { uploads } = state;

  return {
    ...state,
      uploads: updateItemReaction(action.itemid, action.reaction, uploads),
    };
  }
///...

где updateItemReaction — функция, определяемая как:

function updateItemReaction(itemid, reaction, uploads) {
  const upload = uploads.get(itemid)
  const uploadUpdate = {
    ...upload,
    reactions: {
      ...upload.reactions,
      [reaction]: upload.reactions[reaction] + 1
    }
  }

  uploads.set(itemid, uploadUpdate)
  return uploads;
}

Now, while the above way is how you go seeing that the object in store is a Map. Care must be taken to update only the part of the store that changed so that only components using values from that part of the store are re-rendered.

I strongly recommended considering usage of immutable data structures for your component state or strictly treating the store to be immutable by using plain objects.

Я обновил изменения в соответствии с вашими шагами. Пожалуйста, проверьте отредактированный код выше. Событие клика не отображается

Ada 28.04.2019 15:01

О, я понимаю, почему. Свойство onClick должно быть установлено как функция. Как есть, он вызывается немедленно и устанавливается в значение, возвращаемое функцией отправки.

Oluwafemi Sule 28.04.2019 15:10

Там написано Cannot read property 'get' of undefined и я полагаю, это то, что вы имеете в виду onClick = {() => updateReaction(item._id, reaction)}

Ada 28.04.2019 15:17
uploads устанавливается в state, насколько я вижу, и деструктурируется из него в редюсере. Возможно, эта ошибка вызывается строкой console.info(updateItemReactions());.
Oluwafemi Sule 28.04.2019 15:22

Без проблем. Огромное спасибо. Будет отлаживать.

Ada 28.04.2019 15:25

Если вы обнаружите, что количество реакций не обновляется, это может быть связано с тем, что только часть reactions обновляется до нового объекта, и поэтому React не отображает IconText с обновленным значением для реакций. Вы можете исправить это, заменив upload новым объектом, который копирует свое содержимое и обновляет reactions в нем в updateItemReaction.

Oluwafemi Sule 28.04.2019 19:22

Другие вопросы по теме