Reactjs 如何在不更新存储的情况下将成功状态传递回组件

Reactjs 如何在不更新存储的情况下将成功状态传递回组件,reactjs,redux,react-redux,Reactjs,Redux,React Redux,我在react redux中有一个简单的表单,用于尝试向数据库添加用户,如果成功,则显示一条成功消息。然而,我不确定这样做的最佳方法。我有以下资料: onSubmit = e => { ... const newUser = { user object here } this.props.registerUser(newUser); } 在组件将接收道具(下一步): 在渲染()中: 用于显示一个成功组件,提供更多信息。如果成功,还有一个条件检查来隐藏表单 在我的操作中: .t

我在react redux中有一个简单的表单,用于尝试向数据库添加用户,如果成功,则显示一条成功消息。然而,我不确定这样做的最佳方法。我有以下资料:

onSubmit = e => {
  ...
  const newUser = { user object here }
  this.props.registerUser(newUser);
}
组件将接收道具(下一步)

渲染()中
: 用于显示一个成功组件,提供更多信息。如果成功,还有一个条件检查来隐藏表单

在我的
操作中

.then(res => {
  dispatch({
    type: REGISTRATION_SUCCESS,
    payload: true
  });
})
减速器中

const initialState = false;

export default function(state = initialState, action) {
  switch (action.type) {
    case REGISTRATION_SUCCESS:
      return action.payload;
    default:
      return state;
  }
}
在组合传感器中:

export default combineReducers({
  success: successReducer
});
在这种情况下,我基本上使用服务器的响应向组件发送一个成功道具,更新状态,这将强制react渲染并再次遍历条件语句,隐藏表单并显示新的成功块


然而,当我进入redux开发工具时,我看到商店中的状态现在是
true
,如果用户离开,状态仍然是这样。有没有更好的方法来实现这一目标?我发现这可能应该与组件状态本身隔离,但不确定如何做到这一点,因为操作和服务器响应都是通过redux实现的

Redux是一个状态机,而不是一个消息总线,因此请尝试使您的状态值表示应用程序的当前状态,而不是发送一次性消息。这些可以通过操作创建者的返回值进行修改。成功或失败可能仅仅是因为存在/缺少来自动作创建者的错误

如果您确实想要存储用户信息,您可以通过拥有注册用户来派生“was successful”状态,并清除组件装载上的任何现有注册用户

// 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} />
    }
  }
}
//actions.js
导出常量clearRegisteredUser=()=>({
类型:设置\注册\用户,
有效载荷:空,
})
导出常量寄存器=(用户数据)=>async(分派)=>{
//异步函数隐式返回一个承诺,但
//如果使用.then语法,则可以在末尾返回它
const registeredUser=await api.registerUser(userData)
派遣({
类型:设置\注册\用户,
有效载荷:registeredUser,
})
}
//reducer.js
常量initialState={registeredUser:null}
const reducer=(state=initialState,{type,payload})=>{
开关(类型){
案例集\注册\用户:{
返回{
……国家,
registeredUser:有效载荷,
}
}
默认值:{
返回状态
}
}
}
//TestComponent.js
类ExampleComponent扩展组件{
状态={
注册错误:null,
}
组件willmount(){
this.props.clearRegistered()
}
handleSubmit=async(formData)=>{
试一试{
此.props.register(formData)
}捕获(错误){
//不会真正改变应用程序状态,只是
//临时表单状态,所以本地状态是可以的
this.setState({registrationError:error.message})
}
}
render(){
const{registrationError}=this.state
const{registeredUser}=this.props
如果(注册错误){
返回{registrationError}
}else if(registeredUser){
返回
}否则{
返回
}
}
}
如果注册后确实不需要用户信息,可以直接执行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} />
    }
  }
}
类示例组件扩展组件{
状态={
注册:假,
注册错误:null,
}
handleSubmit=async(formData)=>{
试一试{
等待api.registerUser(formData)
this.setState({registered:true})
}捕获(错误){
this.setState({registrationError:error.message})
}
}
render(){
const{registered,registrationError}=this.state
如果(注册错误){
返回{registrationError}
}否则,如果(已注册){
返回
}否则{
返回
}
}
}

最后,尽可能避免在组件状态中保留redux状态的副本。它很容易导致同步问题。这里有一篇关于避免派生状态的好文章:

首先,我认为您不应该使用Redux存储来保存本质上是本地状态的内容

如果是我,我可能会尝试直接从组件进行api调用,如果成功,然后写入redux存储。这样可以避免在组件中使用派生状态


也就是说,如果您想这样做,我建议componentWillUnmount。这将允许您进行另一个Redux调用,当您离开页面时,该调用会将您的注册布尔值恢复为false

在发送注册成功之前,我建议您发送一个请求操作,可能是注册请求。请求操作应将成功字段设置为false。稍后我将尝试返回答案-但请查看我的这个问题-以及其中的链接:-我将其称为挂起/加载/成功/失败模式。API调用是否成功,不是本地状态。
export default combineReducers({
  success: successReducer
});
// 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} />
    }
  }
}
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} />
    }
  }
}