глобальное состояние не будет обновляться редуктором диспетчеризации - PullRequest
0 голосов
/ 27 мая 2018

index.js

import React from 'react';
import {
  AppRegistry
} from 'react-native'
import App from './App';

import { YellowBox } from 'react-native';
YellowBox.ignoreWarnings(['Warning: isMounted(...) is deprecated', 'Module RCTImageLoader']);

AppRegistry.registerComponent('mhagora', () => App);

App.js

import React, { Component } from 'react';
import { Provider } from "react-redux";

import store from './app/store';
import { StyleProvider, getTheme } from "native-base";
import Setup from "./app/setup";
import variables from "./app/theme/variables/commonColor";

export default class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <StyleProvider style={getTheme(variables)}>
          <Setup />
        </StyleProvider>
      </Provider>
    );
  }
}

. / App / setup.js

import React, { Component } from "react";
import axios from "axios/index";
import Config from "./config";
import { Root } from "native-base";

import AppNavigator from "./routes";

axios.defaults.baseURL = Config.API_BASE_URL;
axios.defaults.headers.common['Content-Type'] = Config.API_ACCEPT;
axios.defaults.headers.common['Accept'] = Config.API_ACCEPT;
axios.defaults.headers.common['secret'] = Config.API_SECRET;

export default class Setup extends Component {
  render() {
    return (
      <Root>
        <AppNavigator />
      </Root>
    );
  }
}

. / App / store / index.js

import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import { createLogger } from 'redux-logger';

import reducers from '../reducers';

const logger = createLogger();

export default createStore(reducers, compose(applyMiddleware(thunk, logger)));

. / App / actions / index.js

import { APP_LOADING, APP_LOADED } from '../actionTypes';

export function appLoading() {
  return (dispatch) => {
    dispatch({type: APP_LOADING});
  }
}

export function appLoaded() {
  return (dispatch) => {
    dispatch({type: APP_LOADED});
  }
}

. / App / actions / user.js

import { USER_LOADING, USER_LOADED, USER_FAILED, APP_LOADING, APP_LOADED } from "../actionTypes";
import axios from 'axios';
import Config from '../config';

export function userLogin(username, password) {
  return (dispatch) => {
    dispatch({type: USER_LOADING});
    axios
      .post("oauth/token", {
        username: username,
        password: password,
        client_id: Config.API_CLIENT_ID,
        client_secret: Config.API_CLIENT_SECRET,
        grant_type: 'password',
      }, {
        headers: {}
      })
      .then(response => {
        dispatch({
          type: USER_LOADED,
          data: response.data
        });
      })
      .catch(err => {
        dispatch({ type: USER_FAILED, error: err.response.data.message });
        alert(err.response.data.message);
      });
  };
}

. / App / redurs / index.js

import appReducer from './appReducer';
import userReducer from './userReducer';
import { combineReducers } from "redux";

const rootReducer = combineReducers({
  appReducer,
  userReducer
});

export default rootReducer;

. / App / redurs / userReducer.js

import { USER_LOADING, USER_LOADED, USER_FAILED } from '../actionTypes';
const initialState = {
  username: "",
  password: "",
  user: {}
};

export default userReducer = (state = initialState, action) => {
  switch (action.type) {
    case USER_LOADING:
      return Object.assign({}, state, {
        loading: true,
        user: {},
      });
    case USER_LOADED:
      return Object.assign({}, state, {
        loading: false,
        user: action.data
      });
    case USER_FAILED:
      return Object.assign({}, state, {
        loading: false,
      });
    default:
      return state
  }
}

. / App / redurs / appReducer.js

import { APP_LOADING, APP_LOADED } from "../actionTypes";

const initialState = {
  loading: true,
};

export default appReducer = (state = initialState, action) => {
  switch (action.type) {
    case APP_LOADING:
      return Object.assign({}, state, {
        loading: true
      });
    case APP_LOADED:
      return Object.assign({}, state, {
        loading: false
      });
    default:
      return state;
  }
};

. / App /screen / home.js

'use strict';

import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { SkypeIndicator } from 'react-native-indicators';

import * as Actions from '../actions/index';
import { Container, Header, Title, Content, Footer, FooterTab, Button, Left, Right, Body, Icon, Text, View } from 'native-base';

class HomeScreen extends Component {
  componentDidMount() {
    /** HERE, the apps should show a loading page forever but it didn't **/
    // setTimeout( _ => {
      // this.props.appLoaded();
    // }, 2000);
  }

  render() {
    if (this.props.loading) {
      return (
        <SkypeIndicator />
      );
    } else {
      return (
        <Container>
          <Header>

          </Header>
          <Body>
            <Button
              onPress={() =>
                this.props.navigation.navigate('LoginScreen')
              }><Text>Login now</Text></Button>
            <Text>Hello</Text>
          </Body>
        </Container>

      );
    }
  }
}

// The function takes data from the app current state,
// and insert/links it into the props of our component.
// This function makes Redux know that this component needs to be passed a piece of the state
function mapStateToProps(state, props) {
  return {
    loading: state.loading,
    user: state.user,
  }
}

// Doing this merges our actions into the component’s props,
// while wrapping them in dispatch() so that they immediately dispatch an Action.
// Just by doing this, we will have access to the actions defined in out actions file (action/homeScreen.js)
function mapDispatchToProps(dispatch) {
  return bindActionCreators(Actions, dispatch);
}

//Connect everything
export default connect(mapStateToProps, mapDispatchToProps)(HomeScreen);

. / App /screen / loginScreen

'use strict';

import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import { SkypeIndicator } from 'react-native-indicators';
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import { Body, Button, Container, Content, Header, Icon, Left, Text, Title, View } from "native-base";
import t from 'tcomb-form-native';
import { LoginUserModel, LoginUserModelOption } from "../models/UserModel";
import styles from '../styles';
import LoadingButton from 'react-native-loading-button';
import * as UserActions from '../actions/user';

const Form = t.form.Form;

const ps = StyleSheet.create({
  ...styles,
  container: {
    justifyContent: 'center',
    marginTop: 50,
    padding: 20
  },
});

class LoginScreen extends Component {
  constructor(props) {
    super(props);
  }
  onSubmitHandler = () => {
    const value = this._form.getValue();

    if(value) {
      this.props.userLogin(value.username, value.password);
    }
  };

  render() {
    return (
      <Container>
        <Header>
          <Left>
            <Button transparent onPress={() => this.props.navigation.goBack()}>
              <Icon name="arrow-back"/>
            </Button>
          </Left>
          <Body>
          <Title>Headers</Title>
          </Body>
        </Header>
        <Content padder>
          <View style={ps.container}>
            <Form ref={c => this._form = c} type={LoginUserModel} options={LoginUserModelOption} />
            <LoadingButton
              block
              onPress={this.onSubmitHandler.bind(this)}
              isLoading={this.props.loading}
              style={{ justifyContent: 'center' }}
            ><Icon name="checkmark"/><Text>Login Now</Text></LoadingButton>
          </View>
        </Content>
      </Container>
    );
  }
}

// The function takes data from the app current state,
// and insert/links it into the props of our component.
// This function makes Redux know that this component needs to be passed a piece of the state
function mapStateToProps(state, props) {
  return {
    loading: state.loading,
    user: state.user,
  }
}

// Doing this merges our actions into the component’s props,
// while wrapping them in dispatch() so that they immediately dispatch an Action.
// Just by doing this, we will have access to the actions defined in out actions file (action/homeScreen.js)
function mapDispatchToProps(dispatch) {
  return bindActionCreators(UserActions, dispatch);
}

//Connect everything
export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen);

homeScreen должен приводить к постоянной загрузке страницы, но это не

кнопка loginScreen должна автоматически загружаться при нажатии, но она не

нова для реагирования на родную, я пыталсяустановить / играть с состоянием / реквизитом, но это просто кажется не меняющимся / связанным, у меня также есть другая страница, пытающаяся проверить, синхронизируется ли состояние, но результаты, как всегда, получают свежее состояние, как я понимаю, статистикаЭто что-то вроде ГЛОБАЛЬНАЯ переменная, доступная в любом компоненте, подключаемом к redux

МОЙ ВОПРОС IS 1. Правильно ли настроена собственная реакция / избыточного / избыточного thunk?если нет, то где же ошибка 2. Является ли состояние / реквизиты глобально доступным в любом компоненте, который соединяется с приставкой 3. Если оператор 2 верен, что отличается между состоянием / реквизитом?this.state и this.props 4. Я не очень понимаю работу с обещаниями, как мы можем обработать / подождать, пока вызов API завершится (успех / ошибка), прежде чем перейти к следующему шагу / потоку, я часто использую php и мойлогика застревает в каждой функции, которая должна что-то возвращать, затем зависит от процесса обработки результатов до следующей функции ... и затем ...

Ваш ответ / драгоценное время, потраченное на чтение этого вопроса, приветствуется, спасибо

создан GitHub для легкого воспроизведения / тестирования

https://github.com/weiloon1234/react-native-test

enter image description here

...