我在redux状态树中有一个名为“leagues”的reducer,它只是一个单独的联盟对象数组。每个联盟都有一个唯一的ID(在后端分配)和一个名字。
我正在尝试编写一个代表个人联盟的组件,所以我希望有一个mapStateToProps函数来检索正确的联赛。从url知道正确的联盟,即通过react-router-v4中的匹配prop。
我试过了:
function mapStateToProps(state, ownProps) {
return {
league: state.leagues.find(aLeague => aLeague.id === ownProps.match.params.id)
}
}
但是这导致了一个错误“state.leagues.find”不是一个函数。
然后我试了
function mapStateToProps(state, ownProps) {
return {
league: state.leagues[ownProps.match.params.id]
}
}
哪个没有错误,但检索错误的联盟 - 如果id为3,那么这将检索state.leagues [3],而不是state.leagues.where(league.id === 3)
当我尝试访问单个联盟的页面时,联赛的价值:
leagues: [
{
id: 54,
name: 'Test League'
},
{
id: 55,
name: 'Another Test'
}
],
联盟减速机代码:
const initialState = {
leagues: []
};
export default (state = initialState, action = {}) => {
switch(action.type) {
case SET_USER_LEAGUES:
return state = action.leagues
case ADD_USER_LEAGUE:
return [
...state,
{
id: action.league.id,
name: action.league.name,
}
];
default: return state;
}
}
非常感谢任何帮助。 谢谢!
答案 0 :(得分:2)
这是因为当初始化redux存储时,你最有可能将初始状态设置为null
,这就是为什么你得到错误state.leagues.find
不是一个函数,一旦状态通过一个异步ajax调用然后状态就在那里。我建议在像componentDidMount
这样的反应生命周期方法中制作这种逻辑,并在联盟状态可用后为联盟设置状态。像这样:
componentDidMount() {
const { leagues } = this.state;
if (leagues && leagues.length > 0) {
// update the state to the correct league here and this.props.id is the id that you want
const league = leagues.find(aLeague => aLeague.id === this.props.id);
this.setState({
league
}
}
}
我希望有所帮助。
答案 1 :(得分:1)
似乎在您的组件首次呈现时,其默认状态已设置为null,并且当您尝试在空对象上使用数组方法find
时,该应用程序会崩溃。将联盟减速器的初始状态设置为空数组。
然后,如果您的数组为空,您的应用可能尚未检索到结果,并且您可以显示“正在加载...”这样的消息。
但是,这并不能解决数据库中实际有0个项目的问题。然后,即使有0条记录,你也会显示错误显示加载。
为此,我还建议添加一个isLoading reducer(默认状态为true
),它在获取异步数据期间维护应用程序的状态。异步调用完成后,调度操作以更新appstate并将isLoading设置为false。只有这样你才能尝试从联盟减速器中检索值。
我还建议您使用另一个“联盟”减速器进行过滤,这样您就不必在组件中维护此逻辑。
答案 2 :(得分:0)
我发现IE中不支持Array.prototype.find。因此,可能存在浏览器兼容性问题。
您可以随时使用Array.prototype.filter(假设state.leagues
始终为Array
:
function mapStateToProps(state, ownProps) {
const { leagues = [] } = state;
return {
league: leagues.filter(aLeague => aLeague.id === ownProps.match.params.id)[0]
}
}
答案 3 :(得分:0)
你的减速机对我来说不对劲。你能试试这个:
export default (state = initialState, action = {}) => {
switch (action.type) {
case SET_USER_LEAGUES:
return {
...state,
leagues: action.leagues,
};
case ADD_USER_LEAGUE:
const leagues = [...state.leagues, { id: action.league.id, name: action.league.name, }];
return {
...state,
leagues,
};
default:
return state;
}
}
你的一些函数正在操纵状态,并在返回bool,一个对象和一个数组之间进行更改。
答案 4 :(得分:0)
要解决此问题,我现在使用对象而不是数组。 (原因请参见下面的参考文献1)。在加载商店状态后渲染组件,以便可以使用mapStateToProps。我从工作代码中提取了一些代码摘录。希望还提供了一些有关在此用例中如何使用Redux reducer的技巧。请原谅任何错别字,我在此处内联编辑了代码摘录。
商店
import { createStore, applyMiddleware, combineReducers } from 'redux'
import thunkMiddleware from 'redux-thunk'
import * as reducers from './reducers'
const initialState = {
items: {
/* id(1): {id: PropTypes.number.isRequired, name: PropTypes.string}
id(n): {id: PropTypes.number.isRequired, name: PropTypes.string} */
}
}
var rootReducer = combineReducers(reducers)
window.store = createStore(rootReducer, initialState, applyMiddleware(thunkMiddleware))
动作
export const UPDATE_ITEM = 'UPDATE_ITEM'
export const updateItem = item => ({
type: UPDATE_ITEM,
item
})
减速器
import { UPDATE_ITEM } from './actions'
export const items = (state = null, action) => {
switch (action.type) {
case UPDATE_ITEM:
let id = action.item.id
return Object.assign({}, state, {
[id]: Object.assign({}, state[id], action.item)
})
default:
return state
}
}
向商店添加一些对象
import { updateItem } from './actions'
var item1 = {id: 1, name: 'Alice'}
window.store.dispatch(updateItem(item1))
var item2 = {id: 2, name: 'Bob'}
window.store.dispatch(updateItem(item2))
SomeComponent mapStateToProps
function mapStateToProps (state, ownProps) {
return {
item: state.items[ownProps.id]
}
}
在商店填充后加载这样的组件。
ReactDOM.render(
<Provider store={window.store}>
<SomeComponent id={1} />
<SomeComponent id={2} />
</Provider>,
document.getElementById('root')
)
仅需注意,解决此问题的主要动机是我将整个对象状态(state.items)映射到props,但随后在更新了任何对性能有害的数组元素之后调用了render。 / p>
参考文献: