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

时间:2019-02-05 22:26:17

标签: reactjs redux react-redux

我在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进行的,因此不确定如何执行此操作。

2 个答案:

答案 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。