我在react-redux中有一个简单的表格,试图将用户添加到数据库中,如果成功,则显示成功消息。但是,我不确定执行此操作的最佳方法。我有以下内容:
onSubmit = e => {
...
const newUser = { user object here }
this.props.registerUser(newUser);
}
在componentWillReceiveProps(nextProps)
中:
if (nextProps.success === true) {
this.setState({ success: nextProps.success });
}
在render()
中: 希望显示成功组件,以提供更多信息。如果成功为真,还有一个条件检查可以隐藏表单
{ this.state.success === true &&
(<SuccessComponent name={this.state.name} />)
}
在mapStateToProps
中:
const mapStateToProps = state => ({
success: state.success
});
在我的action
中:
.then(res => {
dispatch({
type: REGISTRATION_SUCCESS,
payload: true
});
})
在reducer
中:
const initialState = false;
export default function(state = initialState, action) {
switch (action.type) {
case REGISTRATION_SUCCESS:
return action.payload;
default:
return state;
}
}
在combineReducers
中:
export default combineReducers({
success: successReducer
});
在这种情况下,我基本上是使用服务器的响应将成功道具分配给组件,更新状态,这会强制做出响应以再次渲染并通过条件语句,从而隐藏表单并显示新的成功块。
但是,当我使用redux开发工具时,我发现商店的状态现在为true
,并且用户应该保持离开状态。有没有更好的方法去实现这个目标?我发现也许应该将其隔离到组件状态本身,但是由于操作以及服务器响应是通过redux进行的,因此不确定如何执行此操作。
答案 0 :(得分:1)
Redux是状态机,而不是消息总线,因此请尝试使您的状态值代表应用程序的当前状态,而不是发送一次性消息。那些可以通过动作创建者的返回值来实现。成功或失败可以简单地是动作创建者是否存在错误。
如果您确实要存储用户信息,则可以通过拥有注册用户来得出“已成功”状态,并清除组件安装上的所有现有注册用户。
// actions.js
export const clearRegisteredUser = () => ({
type: SET_REGISTERED_USER,
payload: null,
})
export const register = (userData) => async (dispatch) => {
// async functions implicitly return a promise, but
// you could return it at the end if you use the .then syntax
const registeredUser = await api.registerUser(userData)
dispatch({
type: SET_REGISTERED_USER,
payload: registeredUser,
})
}
// reducer.js
const initialState = { registeredUser: null }
const reducer = (state = initialState, { type, payload }) => {
switch(type) {
case SET_REGISTERED_USER: {
return {
...state,
registeredUser: payload,
}
}
default: {
return state
}
}
}
// TestComponent.js
class ExampleComponent extends Component {
state = {
registrationError: null,
}
componentWillMount() {
this.props.clearRegistered()
}
handleSubmit = async (formData) => {
try {
this.props.register(formData)
} catch(error) {
// doesn't really change application state, only
// temporary form state, so local state is fine
this.setState({ registrationError: error.message })
}
}
render() {
const { registrationError } = this.state
const { registeredUser } = this.props
if (registrationError) {
return <FancyError>{registrationError}</FancyError>
} else if (registeredUser) {
return <SuccessComponent name={this.props.registeredUser.name} />
} else {
return <UserForm onSubmit={this.handleSubmit} />
}
}
}
如果在注册后确实不需要用户信息,则可以直接执行api调用,而将Redux排除在外。
class ExampleComponent extends Component {
state = {
registered: false,
registrationError: null,
}
handleSubmit = async (formData) => {
try {
await api.registerUser(formData)
this.setState({ registered: true })
} catch(error) {
this.setState({ registrationError: error.message })
}
}
render() {
const { registered, registrationError } = this.state
if (registrationError) {
return <FancyError>{registrationError}</FancyError>
} else if (registered) {
return <SuccessComponent name={this.props.registeredUser.name} />
} else {
return <UserForm onSubmit={this.handleSubmit} />
}
}
}
最后,请尽可能避免在组件状态下保留redux状态的副本。它很容易导致同步问题。这是一篇关于避免派生状态的好文章:https://reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html
答案 1 :(得分:1)
首先,我认为您不应该使用Redux存储来保存实质上的本地状态。
如果是我,我可能会尝试直接从组件进行api调用,如果成功,则将其写入redux存储。这样,您可以避免组件中具有派生状态。
也就是说,如果您想这样做,我建议使用componentWillUnmount。这将允许您进行另一个Redux调用,当您离开页面时,该调用会将您的注册布尔值恢复为false。