下一个状态更改后父级重新渲染

时间:2018-12-24 15:54:56

标签: redux react-redux

我是Redux的新手,似乎有问题。一旦调度了我的操作,该操作就成功了,但是父组件直到进行另一个状态更改后才获得更新的状态。如果单击登录,然后在输入字段中删除一个字符,则会触发状态更改,向我显示菜单。非常感谢任何帮助/指针,谢谢。

主要(父母):

import React, { Component } from 'react'
import { connect } from 'react-redux'

import Login from '../login'
import Menu from '../menu'

type Props = { token: string }
class Main extends Component<Props, {}> {
  render() {
    const { token } = this.props;

    if (!token) {
      return (
        <Login />
      )
    }

    return (
      <Menu />
    )
  }
}

const mapStateToProps = (state) => ({
  token: state.session.token,
})

export default connect(
  mapStateToProps,
  null,
)(Main)

登录(儿童):

import React from 'react'
import { connect } from 'react-redux'

import { login } from '../../redux/session/session.actions'

import { View, StyleSheet } from 'react-native'
import { Button, FormLabel, FormInput, FormValidationMessage } from 'react-native-elements'

import styled from 'styled-components/native'

const Container = styled(View)`
    flex: 1;
    flex-direction: column;
    justify-content: center;
    align-items: center;
`

const Wrapper = styled(View)`
    width: 300;
`

type Props = { login: Function, error: string, loading: boolean };
type State = { email: string, password: string };

class Login extends React.PureComponent<Props, State> {
    constructor(props) {
        super(props);

        this.state = {
            email: null,
            password: null,
        }
    }

    render() {
        console.log('props', this.props);
        console.log('state', this.state);
        const { loading, error } = this.props;

        return (
            <Container>
                <Wrapper>
                    <FormValidationMessage>{loading ? 'Loading...' : null}</FormValidationMessage>
                    <FormValidationMessage>{error ? 'Unable to login, please try again.' : null}</FormValidationMessage>
                    <FormLabel>Email:</FormLabel>
                    <FormInput onChangeText={text => this.setState({ email: text })} />
                    <FormLabel>Password:</FormLabel>
                    <FormInput secureTextEntry onChangeText={password => this.setState({ password })} />
                    <Button title='Login' onPress={this.login} />
                </Wrapper>
            </Container>
        )
    }

    login = () => {
        this.props.login(this.state.email, this.state.password);
    }
}

const mapStateToProps = (state) => {
    console.log(state);
    return {
        error: state.session.error,
        loading: state.session.loading
    }
}

const mapDispatchToProps = ({
   login
})

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(Login);

减速器:

import {
    LOGGING_IN,
    LOGIN_SUCCESS,
    LOGIN_FAILED
  } from './session.types'

  const initialState = {
    loading: null,
    error: null,
    token: null,
  }

  export default (state = initialState, { type, payload }) => {
    switch (type) {

      case LOGGING_IN:
        return { 
          ...state, 
          loading: true
        }

      case LOGIN_SUCCESS:
        return { 
          ...state,
          loading: false,
          error: null,
          token: payload.token
        }

      case LOGIN_FAILED:
        return { 
          ...state, 
          loading: false,
          error: payload.error  
        }

      default:
        return state
    }
  }

操作:

import { API_URL } from '../../../app-env'
import axios from 'axios'

import {
  LOGGING_IN,
  LOGIN_SUCCESS,
  LOGIN_FAILED
} from './session.types'

export const login = (email, password) => (
  async dispatch => {
    console.log('here');
    dispatch(loggingIn());

    await axios.post(`${API_URL}/login`, {
      email,
      password
    }).then(res => {
      dispatch(loginSuccess(res.data.token))
    }).catch(err => {
      dispatch(loginFailed('Unable to login.'))
    })
  }
)

export const loggingIn = () => ({
  type: LOGGING_IN,
})

export const loginSuccess = (token) => ({
  type: LOGIN_SUCCESS,
  payload: {
    token
  }
})

export const loginFailed = (error) => ({
  type: LOGIN_FAILED,
  payload: {
    error
  }
})

1 个答案:

答案 0 :(得分:0)

由于您的问题是有关Menu无法渲染并且MenuMain下。因此,我们可以问一个问题,Main组件不重新呈现。幸运的是,您的示例Main仅取决于一个道具,而没有任何状态。 -我会说您的问题出在props.token上。-由于您将令牌初始化为null,因此我假设它具有对象类型。在这种情况下,您需要确保令牌需要是一个新对象(新引用),否则不能重新渲染,因为默认情况下,react-redux connect将在触发其下方的组件之前检查道具更改。 / p>

编辑:您提到Menu未显示且令牌为字符串,我可以想到另一个未渲染Main的原因是因为connect未触发。您可能需要检查存储的根目录,并确保它具有新的引用,因为您的代码仅显示了reducer更新state.session,而不显示状态本身。