【问题标题】:React Component render not called first time with redux使用 redux 首次未调用 React Component 渲染
【发布时间】:2017-09-25 21:46:56
【问题描述】:

我正在尝试通过执行以下操作将用户重新路由到用户尝试在浏览器地址栏上导航的 url: 我通过调用服务方法检查用户是否登录。如果 cookie 中的 session 过期或者无效,会返回 401 状态,我会重定向到登录界面

  1. 如果用户已登录,则允许。

  2. 如果用户未登录,则路由到登录屏幕,登录后,路由到所需的 url。

这里的问题是,当用户输入如下网址时:http://url/app/order 它被重定向到登录 URL:http://url/auth/login 在用户输入他的凭据后,虽然操作被调度,但 Authorizedroute 组件的渲染不会被调用。在我再次点击登录按钮后它会被调用。

以下是我的登录组件

export class LoginForm extends React.Component {

componentWillReceiveProps(newProps){

    const { location, isAuthenticated, history } = newProps;
    if(isAuthenticated){

        if(location.state && location.state.referrer){
           history.push(location.state.referrer.pathname);
        }else{
            history.replace('/app');
        }
    }
}

render() {
    let usernameInput, passwordInput;
    const { showErrorMessage, errorMessage, onLogin } = this.props;
    return  (


        <div className='sme-login-center-view-container'>
            <HeaderComponent />

            <Col lg={4} lgOffset={4} sm={12} xs={12}>
                <Col lg={10} lgOffset={2} sm={4} smOffset={4}>
                    <Form className="sme-login-box" onSubmit={(e)=> {
                                                        e.preventDefault();
                                                        let creds = {username: usernameInput.value, password: passwordInput.value};
                                                        onLogin(creds);                                            
                                                    }
                                                }>

                            <span className='text-center sme-login-title-text'><h4>User Login</h4></span>

                        <FormGroup >                    
                            {errorMessage ? (<Alert bsStyle="danger"><strong>Error!</strong> {errorMessage}</Alert>) : null }
                        </FormGroup>

                        <FormGroup controlId="formHorizontalUsername">                    
                            <FormControl type="username" placeholder="Username" bsStyle="form-rounded"
                                inputRef={(ref) => {usernameInput = ref}}
                            />                
                            <FormControl.Feedback>
                                <span className="fa fa-user-o sme-login-input-feedback-span"></span>
                            </FormControl.Feedback>            
                        </FormGroup>

                        <FormGroup controlId="formHorizontalPassword">                   
                            <FormControl type="password" placeholder="Password" 
                                inputRef={(ref) => {passwordInput = ref}}/>                                   
                            <FormControl.Feedback>
                                <span className="fa fa-lock sme-login-input-feedback-span"></span>
                            </FormControl.Feedback>
                        </FormGroup>

                        <FormGroup>              
                            <Button type="submit" block >Login</Button>              
                        </FormGroup>

                    </Form>
                </Col>
            </Col>
        </div>

    );
}
}

登录容器

const mapStateToProps = state => {
    return state.authenticationReducer.login
}

export const Login = withRouter(connect( mapStateToProps,{ onLogin: loginUser })(LoginForm))

登录操作

export function requestLogin(creds) {
  return {
    type: LOGIN_REQUEST,
    isFetching: true,    
    isAuthenticated: false,
    creds
  }
}
export function receiveLogin() {
  return {
    type: LOGIN_SUCCESS,
    isFetching: false,
    isAuthenticated: true
  }
}
export function loginError(message) {
  return {
    type: LOGIN_FAILURE,
    isFetching: false,
    isAuthenticated: false,
    errorMessage: message
  }
}
export function loginUser(creds) {   
  return dispatch => {    
    dispatch(requestLogin(creds))    
        return axios.post(url, data)
            .then(response => {
                if (!response.status === 200) {                    
                    dispatch(loginError(response.statusText))                    
                } else {
                    dispatch(receiveLogin())
                }
            }
       ).catch(function (error) {
            dispatch(loginError(error.response.statusText))
        }
    )  }
    }

登录缩减器:

export function login(state = {
        isFetching: false,
        isAuthenticated: false
      }, action) {

      switch (action.type) {
        case LOGIN_REQUEST:
        case LOGIN_SUCCESS:
        case LOGIN_FAILURE:
          return Object.assign({}, state, action)
        default:
          return state
      }
    }

授权路由组件

class AuthorizedRouteComponent extends React.Component {

  componentWillMount() {
    this.props.getUser();
  }
  render() {
    const { component: Component, pending, logged, location, ...rest } = this.props;
    return (
      <Route {...rest} render={props => {
        if (pending) return <div>Loading...</div>
            return logged
              ? <Component {...this.props} />
              :<Redirect to={{
                  pathname: '/auth/login',
                  state: { referrer: location }
            }}/>
          }} />
        )
      }
    }

    const mapStateToProps = state => {  
      return state.authenticationReducer.loggedUser
    }

    const AuthorizedRoute = connect(mapStateToProps, { getUser: getLoggedUser })(AuthorizedRouteComponent);

    export default AuthorizedRoute

查找记录的用户操作

    export function requestFetch() {
  return {
    type: FETCH_REQUEST,    
    pending: true,    
    logged: false
  }
}
export function receiveFetch(userData) {
  return {
    type: FETCH_SUCCESS,
    pending: false,
    logged: true,
    userData
  }
}
export function fetchError(message) {
  return {
    type: FETCH_FAILURE,
    pending: false,
    logged: false,
    errorMessage:message
  }
}
export function getLoggedUser() {  
  return dispatch => {    
    dispatch(requestFetch())
    return axios.get('/o3/rest/user/userdetails')
            .then(response => {

                if (!response.status === 200) {
                  dispatch(fetchError(response.statusText))                  
                } else {
                  dispatch(receiveFetch(response.data))
                }
            }
       ).catch(function (error) {
            dispatch(fetchError(error.response.statusText))
          }
        )
  }   
}

最后是我的登录用户减速器

    export function loggedUser(state = initialState, action) {  
  switch (action.type) {
    case FETCH_REQUEST:
    case FETCH_SUCCESS:
    case FETCH_FAILURE:
      let obj = Object.assign({}, state, action);
      return obj;
    default:
      return state
  }
}

【问题讨论】:

    标签: reactjs redux react-router-v4


    【解决方案1】:

    您可以使用 localStorage 将用户保存在您的操作创建者中,该操作创建者负责获取用户:

    export function getLoggedUser() {  
      return dispatch => {    
        dispatch(requestFetch())
        return axios.get('/o3/rest/user/userdetails')
                .then(response => {
    
                    if (!response.status === 200) {
                      dispatch(fetchError(response.statusText))                  
                    } else {
                      localStorage.setItem('userData',response.data)
                    }
                }
           ).catch(function (error) {
                dispatch(fetchError(error.response.statusText))
              }
            )
      }   
    }
    

    然后在索引文件中询问:

    const userData = localStorage.getItem('userData')
    if(userData){
        store.dispatch({
            type: FETCH_SUCCESS,
            pending: false,
            logged: true,
            userData
        })
    }
    

    每次您刷新页面或仅输入一个 URL(如http://url/app/order)时,都会验证当前是否存在登录用户,如果存在将调度操作更新您的状态。

    【讨论】:

    • 刷新浏览器时仅调用一次 userData 服务,我不想将其放在 localStorage 中,因为刷新浏览器时,如果会话过期,我不希望用户看到任何内容o 无效。无论如何,我在帖子中的问题是为什么 AutjorizedRoute 组件的渲染方法在登录后第一次没有被调用,但在再次单击登录按钮时起作用。
    猜你喜欢
    • 2020-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-08
    • 1970-01-01
    • 2019-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多