我使用redux thunk在动作上返回API调用:
export const getActiveCampaigns = () => {
return (dispatch, getState) => {
const bearer = 'Bearer ' + getState().login.bearer
return axios.get(API.path + 'campaign/active/?website_id=' + getState().selectedWebsite.selectedWebsite + '&' + API.beaconAPI_client, { headers: { 'Authorization': bearer } })
.then(function (response) {
dispatch({
type: GET_ACTIVE_CAMPAIGNS,
activeCampaigns: response.data.response
})
})
}
}
这样可以成功地返回一个广告系列列表,我将使用以下内容将其渲染到另一个组件中:
class ActiveCampaignsDropdown extends Component {
// usual stuff
componentDidMount(){
this.props.dispatch(getActiveCampaigns())
}
// render function displays campaigns using this.props.activeCampaigns
}
const mapStateToProps = (state) => {
return {
activeCampaigns: state.activeCampaigns.activeCampaigns
}
}
但是,请注意该操作的getState.selectedWebsite.selectedWebsite
。这是通过应用程序中其他位置的操作设置的,用户从下拉列表中选择网站。我的减速器看起来像这样:
export default function (state = {}, action) {
switch(action.type){
case SET_SELECTED_WEBSITE:
return {
...state,
selectedWebsite: action.websiteId
}
default:
return state;
}
}
export default function (state = {}, action) {
switch(action.type){
case GET_ACTIVE_CAMPAIGNS:
return {
...state,
activeCampaigns: action.activeCampaigns
}
default:
return state;
}
}
我设置所选网站的操作:
export const setSelectedWebsite = (websiteId) => {
return {
type: SET_SELECTED_WEBSITE,
websiteId
}
}
这与其他减速器结合使用:
export default combineReducers({
login,
activeWebsites,
activeCampaigns,
selectedWebsite
})
问题
活动广告系列下拉框的内容在页面加载时工作正常 - 状态树确实更新 - 但在所选网站更改时不会更新。从我所看到的:
我非常失望Redux不是“只是工作”而且#34;在这种情况下,虽然有可能我只是睡了几个小时才能看到傻事!任何帮助表示赞赏。
答案 0 :(得分:2)
在React中,当发生以下三种情况之一时,组件会更新:
在您的情况下,您希望在商店中发生ActiveCampaignsDropdown
更改时更新state.activeCampaigns
。要做到这一点,你必须连接你的组件,使它作为道具接收这个值(并因此在更改时强制更新)。
这可以按如下方式完成:
import {connect} from 'react-redux'
class ActiveCampaignsDropdown extends React.Component { ... }
const mapStateToProps = (state) => ({activeCampaigns: state.activeCampaigns});
const Container = connect(mapStateToProps)(ActiveCampaignsDropdown);
export default Container;
最终Container
组件将通过其道具完成将ActiveCampaignsDropdown
与所需商店状态相关联的所有工作。
Redux的connect()
还允许我们连接调度函数来修改商店中的数据。例如:
// ... component declaration
// ... mapStateToProps
const mapDispatchToProps = (dispatch) =>
{
return {
getActiveCampaigns: () => dispatch(getActiveCampaigns())
};
}
const Container = connect(mapStateToProps, mapDispatchToProps)(ActiveCampaignsDropdown);
一旦定义了映射函数,就会创建容器组件,并呈现容器,ActiveCampaignsDropdown
将被正确连接。在我的示例中,它将接收'activeCampaigns'和'getActiveCampaigns'作为道具,并在其值发生变化时进行相应更新。
修改:
再看一下您的代码后,我认为您的问题是由于在网站发生变化时更新ActiveCampaignsDropdown
没有满足任何条件的事实。通过从您的WebsiteDropdown调用getActiveCampaigns()
(根据您的评论),这会强制state.activeCampaigns
更改,从而成功更新ActiveCampaignsDropdown
。正如我的一条评论中提到的那样,“强迫”这个改变来自一个不负责任的组件,这将被视为不良做法。
一个完全合理的解决方案是ActiveCampaignsDropdown
“监听”当前网站的更改并相应地更新自己。为此,您需要做两件事:
(1)将网站状态映射到组件
const mapStateToProps = (state) => {
return {
activeCampaigns: state.activeCampaigns.activeCampaigns, // unsure why structured like this
selectedWebsite: state.selectedWebsite.selectedWebsite
}
}
(2)将您的调度调用移至componentWillReceiveProps
class ActiveCampaignsDropdown extends React.Component
{
// ...
componentWillReceiveProps(nextProps)
{
if (this.props.selectedWebsite !== nextProps.selectedWebsite)
{
this.props.getActiveCampaigns();
}
}
}
现在每次所选网站发生更改时,都会进行刷新并调用componentWillReceiveProps()
(导致activeCampaigns
也更新)。应用此更新后,将进行另一次刷新,呈现的下拉列表将包含新更新的广告系列。
一些小改进:
如果您的许多组件依赖于当前网站的状态(我想象的很多),那么您可以考虑通过context
向他们提供。
现在您的ActiveCampaignsDropdown
收到'selectedWebsite'作为道具,您可以直接将其传递给您的动作函数,而不是让它从状态(使用getState()
)获取 - 通过如果可能的话,也应该避免这种方式。
答案 1 :(得分:0)
在减速器中存储时使用扩展运算符:
return {
cart: [...cart]
};