我有一个入职的场景,用户可以逐步进行入职培训。我想用Redux管理用户进度的客户端状态。服务器和客户端之间的同步已经在Relay中实现,但我仍然需要一个Redux存储来进行客户端状态管理。因此,同步Relay- / Redux-Store会出现问题。
我现在正在做的是用Redux包装我的React组件,然后用Relay包装:
// OnboardProgressView.js
// ...
// wrap React component with Redux
const mapStateToProps = (state) => {
return {
onboardProgress: state.onboardProgress,
}
}
const ReduxContainer = connect(
mapStateToProps,
)(OnboardProgressView)
// this is only for convenience of access of the Relay data
const MappedOnboardProgressView = mapProps({
params: (props) => props.params,
user: (props) => props.viewer.user,
})(ReduxContainer)
// wrap Redux component with Relay
export default Relay.createContainer(MappedGettingStartedView, {
fragments: {
viewer: () => Relay.QL`
fragment on Viewer {
user {
userId
onboardProgressStep
}
# more stuff ...
}
`,
},
})
我找到了完成不同操作的方法如下:
使用服务器数据初始化Redux商店
我在使用异步原始中继查询创建存储后立即初始化Redux状态。为了实现这一点,我也在使用redux-thunk
中间件。 Redux发起对Relay的请求,该请求查询服务器。视觉表示(箭头表示数据流,元素的顺序反映'呼叫顺序'):Redux <= Relay <= Server
// app.js
const store = createStore(reducer, applyMiddleware(thunk))
store.dispatch(fetchOnboardProgress())
// onboardProgress.js
export function fetchOnboardProgress () {
return function (dispatch) {
var query = Relay.createQuery(Relay.QL`
query {
viewer {
user {
id
onboardProgress
}
}
}`, {})
return new Promise(function (resolve, reject) {
Relay.Store.primeCache({query}, ({done, error}) => {
if (done) {
const data = Relay.Store.readQuery(query)[0]
dispatch(update(data.user.onboardProgress, data.user.id))
resolve()
} else if (error) {
reject(Error('Error when fetching onboardProgress'))
}
})
})
}
}
在分派Redux操作时更新服务器上的数据
Redux => Relay => Server
为了获得一致的状态更改,当用户进行新手入门过程时,我会触发一个Redux操作,该操作也将异步执行Relay突变。我也在为此目的使用redux-thunk
。
function nextStep () {
return function (dispatch, getState) {
const currentStep = getState().onboardProgress.step
const currentStepIndex = OnboardProgress.steps.indexOf(currentStep)
const nextStep = OnboardProgress.steps[currentStepIndex + 1]
const userId = getState().onboardProgress._userId
return _updateReduxAndRelay(dispatch, nextStep, userId)
}
}
function _updateReduxAndRelay (dispatch, step, userId) {
return new Promise((resolve, reject) => {
Relay.Store.commitUpdate(new UpdateUserMutation({
userId: userId,
onboardProgressStep: step,
}), {
onSuccess: () => {
dispatch(update(step, userId))
resolve()
},
onFailure: reject,
})
})
}
export function update (step, userId) {
const payload = {onboardProgress: new OnboardProgress({step, userId})}
return {type: UPDATE, payload}
}
我仍然没有找到解决以下问题的方法:
在中继商店更新时更新Redux商店
服务器上的数据更改可能包含外部源,这些外部源不是由我们的应用中的用户操作触发的。使用Relay,我们可以通过forceFetching或polling来解决这个问题。中继查询如下所示:Relay <= Server
。我想在外部数据发生变化时另外拥有此数据流:Relay => Redux
。
需要使用新数据更新Redux存储的另一个可能原因是我们想要同步深度嵌套在中继存储中的数据,或者是复杂查询的一部分。
例如,考虑博客帖子的评论数量。当用户发布新评论时,显示评论计数的另一个组件也应该更新。
如果我们在Redux中管理这些信息,我们需要一种方法来在Relay查询附带新信息时触发Redux操作。我不知道这种回调,或其他解决方案。
在这种情况下,我有这些问题: