Родительский рендеринг после следующего изменения состояния - PullRequest
0 голосов
/ 24 декабря 2018

Я новичок в Redux, и у меня возникла проблема.Как только мое действие было отправлено, оно успешно, однако родительский компонент не получает обновленное состояние, пока не будет сделано другое изменение состояния.Если я нажимаю на кнопку «Войти», затем удаляю символ в поле ввода, то происходит изменение состояния, показывая мне меню.Любая помощь / указатели высоко ценятся, спасибо.

Main (родитель):

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 голосов
/ 25 декабря 2018

Так как ваша проблема о Menu, не отображается, а Menu ниже Main.Итак, мы можем задать вопрос, какое условие Main компонента не перерисовать.К счастью, ваш пример Main зависит только от одного реквизита и без состояния.-Я скажу, что ваша проблема лежит на props.token.- Поскольку вы инициализируете свой токен как null, я предполагаю, что он содержит тип объекта.В этом случае вам необходимо убедиться, что токен должен быть новым объектом (новая ссылка), иначе не нужно выполнять повторную визуализацию, потому что по умолчанию response-redux connect проверит изменения реквизита, прежде чем запускать компонент под ним.

РЕДАКТИРОВАТЬ: Вы упомянули, что Menu не отображается, и токен является строкой, я могу вспомнить другую причину, по которой Main не отображается, потому что connect не является триггером.Возможно, вам нужно проверить корневой каталог хранилища и убедиться, что в нем есть новая ссылка, поскольку в вашем коде отображается только состояние обновления редуктора, но не само состояние.

...