我正在使用React和Redux创建freecodecamp twitch API。该应用程序的想法是,您可以搜索要关注的频道,这些频道将添加到“朋友列表”中。在好友列表的顶部是一个包含3个切换功能的按钮组:全部显示,在线显示和离线显示。
我正试图找出最好的方法来做到这一点。目前,我的“用户”状态只是一个用户数组,每个用户都是一个包含2个键的对象:channelData
和streamData
。
这是因为我必须对twitch API进行2次axios调用:一次是获取一般频道信息(例如徽标网址,频道名称),另一种是查看频道当前是在线还是离线。< / p>
actions/index.js
:
import axios from 'axios';
export const FETCH_USER = 'FETCH_USER';
export const HAS_ERRORED = 'HAS_ERRORED';
export const SELECTED_USER = 'SELECTED_USER';
export const SHOW_ONLINE = 'SHOW_ONLINE';
export const SHOW_OFFLINE = 'SHOW_OFFLINE';
export const SHOW_ALL = 'SHOW_ALL';
const ROOT_URL = 'https://wind-bow.glitch.me/twitch-api/';
export function fetchUser(user) {
const channelUrl = `${ROOT_URL}/channels/${user}`;
const streamUrl = `${ROOT_URL}/streams/${user}`;
const request = axios.all([
axios.get(channelUrl),
axios.get(streamUrl)
]);
return (dispatch) => {
request.then(axios.spread((channelData, streamData) => {
var channelData = channelData.data;
var streamData = streamData.data;
if (channelData.error) {
dispatch(hasErrored(channelData.message));
}
else {
dispatch({
type: FETCH_USER,
payload: { channelData, streamData }
});
dispatch(hasErrored(null));
}
}));
}
}
export function hasErrored(msg) {
return {
type: HAS_ERRORED,
msg
}
}
export function selectUser(user) {
return (dispatch) => {
dispatch(hasErrored(null));
dispatch({
type: SELECTED_USER,
user
});
}
}
export function showOnline() {
return {
type: SHOW_ONLINE
}
}
export function showOffline() {
return {
type: SHOW_OFFLINE
}
}
export function showAll() {
return {
type: SHOW_ALL
}
}
然后,当依赖于单击哪个按钮时,将执行SHOW_ALL,SHOW_ONLINE或SHOW_OFFLINE操作,此时只需过滤 当前状态,以查看该用户的streamData是否显示它是否在线。但是这种方法的问题是当我点击一个按钮,例如SHOW_ONLINE,它将列出所有在线用户,并且不会在某处存储所有离线用户,因此当我在此之后单击SHOW_OFFLINE时,
reducers/reducer_users.js
:
import { FETCH_USER, SHOW_ONLINE, SHOW_OFFLINE, SHOW_ALL } from '../actions/index';
export default function(state = [], action) {
switch(action.type) {
case FETCH_USER:
return [action.payload, ...state];
case SHOW_ONLINE:
return state.filter(user => {
return user.streamData.stream;
});
case SHOW_OFFLINE:
return state.filter(user => {
return !user.streamData.stream;
});
case SHOW_ALL:
return state;
}
return state;
}
containers/users_list.js
:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { selectUser, showOnline, showOffline, showAll } from '../actions/index';
class UsersList extends Component {
renderUser(user) {
const { channelData, streamData } = user;
return (
<tr
key={channelData.display_name}
onClick={() => this.props.selectUser(user)}
className='list-item'>
<td>
<img src={channelData.logo} className='user-logo' />
</td>
<td>
{channelData.display_name}
</td>
<td>
{streamData.stream ?
<span className='online'>Online</span> :
<span className='offline'>Offline</span>}
</td>
</tr>
)
}
render() {
console.log('state:', this.props.users);
return (
<div className='col-sm-4'>
<div className='text-center'>
<div className='btn-group btn-group-sm' role='group'>
<button
className='btn btn-default'
onClick={this.props.showAll}>
All
</button>
<button
className='btn btn-default'
onClick={this.props.showOnline}>
Online
</button>
<button
className='btn btn-default'
onClick={this.props.showOffline}>
Offline
</button>
</div>
</div>
<table className='table table-hover'>
<thead>
<tr>
<th>Logo</th>
<th>Channel</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{this.props.users.map(this.renderUser.bind(this))}
</tbody>
</table>
</div>
)
}
}
function mapStateToProps({ users }) {
return { users };
}
export default connect(mapStateToProps, { selectUser, showOnline, showOffline, showAll })(UsersList);
答案 0 :(得分:0)
如果我理解正确,你的问题就是排序,过滤等问题,同时保持对原始状态的参考。
考虑以下问题:
let arr = [1,2,3,4];
let newArr = arr.filter((item)=>{ return item > 2 });
newArr
(在您的情况下,这是您的新状态)现在缺少项目。如果您想查看原始列表,则无法进行。
您需要在对数据进行任何修改之前保留一份干净的数据副本,这样每当您进行过滤时,您总是重新开始。
更简单的减速器看起来像这样
function(state = {}, action) { //notice state is an object
switch(action.type) {
case FETCH_USER:
let newState = Object.assign({},state);
newState['pristine'] = Object.assign({},action.payload);
newState['filteredData'] = Object.assign({},action.payload);
return newState;
case SHOW_ONLINE:
let data = Object.assign({},state.pristine);
let filteredData = data.filter(user => {
return user.streamData.stream;
});
return Object.assign({},state,{filteredData});
case SHOW_ALL:
return state.pristine;
}
return state;
}
这段代码有很多防御性的Object.assign,远离生产代码,但我希望它能指出你的正确轨道。