我正在使用redux来管理组件的状态,并使用新映射从redux存储访问该组件的对象数组。
当前,我可以同时选择所有图标并按1
递增,这不是理想的选择,因为我不能喜欢某个帖子,但仍然不喜欢同一帖子。因此,例如,如果我单击like
并将其增加1
,然后单击dislike
,则like
的状态会返回到先前的状态。我正在使用updateUploadReaction
函数处理图标。这是link的代码,可提供更好的视图,可以在home
目录下找到。
reducers.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 uploads = new Map();
USER_UPLOADS.forEach(userUpload => {
const { id } = userUpload;
uploads.set(id, userUpload);
});
return uploads;
}
function updateUploadReaction(id, type, uploads) {
const updatedUploads = new Map([...uploads.entries()]);
const userUpload = updatedUploads.get(id);
if (!userUpload.reactions[type]) {
userUpload.reactions[type] += 1;
} else {
userUpload.reactions[type] -= 1;
}
updatedUploads.set(id, userUpload);
return updatedUploads;
}
export default (state = { ...INITIAL_STATE }, action) => {
switch (action.type) {
case REQUEST_UPLOAD_LIST: {
return {
...state,
uploads: generateUploadsMap(),
};
}
case UPDATE_REACTION: {
const { uploads } = state;
const { payload: { id, reaction } } = action;
return {
...state,
uploads: updateUploadReaction(id, reaction, uploads),
};
}
default:
return state;
}
};
constants.js
/** @constant */
export const INITIAL_STATE = {
uploads: new Map(),
};
export const USER_UPLOADS = [
{
id: 0,
// eslint-disable-next-line max-len
image: 'http://sugarweddings.com/files/styles/width-640/public/1.%20The%20Full%20Ankara%20Ball%20Wedding%20Gown%20@therealrhonkefella.PNG',
reactions: {
dislike: 0,
like: 0,
maybe: 0,
},
story: "It's my birthday next week! What do you think?",
user: 'Chioma',
},
{
id: 1,
// eslint-disable-next-line max-len
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,
// eslint-disable-next-line max-len
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',
},
];
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, onClick }) => (
<span>
<Icon type={type} style={ICON} onClick={onClick} />
{text}
</span>
);
function createReactionsIcon(item, updateReaction) {
const { like, dislike, maybe } = item.reactions;
const icons = [
{ key: 'like', text: `${like}`, type: 'heart' },
{ key: 'dislike', text: `${dislike}`, type: 'dislike' },
{ key: 'maybe', text: `${maybe}`, type: 'meh' },
];
return icons.map(({ key, text, type }) => (
<IconText
onClick={() => updateReaction(item.id, key)}
key={key}
type={type}
text={text}
/>
));
}
class Home extends React.Component {
componentDidMount() {
const { actions: { requestUploadList } } = this.props;
requestUploadList();
}
updateReaction = (id, reaction) => {
const { actions: { updateReaction } } = this.props;
const payload = { id, reaction };
updateReaction(payload);
}
render() {
const { uploads } = this.props;
const values = [...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 = {
actions: PropTypes.object,
uploads: PropTypes.instanceOf(Map),
};
const mapStateToProps = state => ({
uploads: getUploads(state),
});
const mapDispatchToProps = dispatch => ({
actions: bindActionCreators(actions, dispatch),
});
export default connect(mapStateToProps, mapDispatchToProps)(Home);