React Native Redux Ignite错误"未检查"使用API

时间:2018-03-28 00:05:10

标签: javascript reactjs react-native redux react-redux

您好我仍然是本土的反应,我很困惑如何使用react redux特别是对于点燃模板。我按照本教程https://medium.com/skyshidigital/interaksi-api-dengan-ignite-react-native-f83bf35a23f5进行操作。这是我最新的错误"未检查"," take(patternOrChannel):patternOrChannel未定义"。请帮忙告诉我代码的哪一部分给我一个错误。

Api.js:

// a library to wrap and simplify api calls
import apisauce from 'apisauce'

// our "constructor"
const create = (baseURL = 'http://localhost:4200/') => {
  // ------
  // STEP 1
  // ------
  //
  // Create and configure an apisauce-based api object.
  //
  const api = apisauce.create({
    // base URL is read from the "constructor"
    baseURL,
    // here are some default headers
    headers: {
      'Cache-Control': 'no-cache'
    },
    // 10 second timeout...
    timeout: 10000
  })

  // ------
  // STEP 2
  // ------
  //
  // Define some functions that call the api.  The goal is to provide
  // a thin wrapper of the api layer providing nicer feeling functions
  // rather than "get", "post" and friends.
  //
  // I generally don't like wrapping the output at this level because
  // sometimes specific actions need to be take on `403` or `401`, etc.
  //
  // Since we can't hide from that, we embrace it by getting out of the
  // way at this level.
  //
  const getRoot = () => api.get('')
  const getRate = () => api.get('rate_limit')
  const getUser = (username) => api.get('search/users', {q: username})
  const getUsers = () => api.get('/users')
  // ------
  // STEP 3
  // ------
  //
  // Return back a collection of functions that we would consider our
  // interface.  Most of the time it'll be just the list of all the
  // methods in step 2.
  //
  // Notice we're not returning back the `api` created in step 1?  That's
  // because it is scoped privately.  This is one way to create truly
  // private scoped goodies in JavaScript.
  //
  return {
    // a list of the API functions from step 2
    getRoot,
    getRate,
    getUser,
    getUsers
  }
}

// let's return back our create method as the default.
export default {
  create
}

UsersRedux.js

import { createReducer, createActions } from 'reduxsauce'
import Immutable from 'seamless-immutable'

/* ------------- Types and Action Creators ------------- */

const { Types, Creators } = createActions({
  usersRequest: null,
  usersSuccess: ['data'],
  usersFailure: null
})

export const UsersTypes = Types
export default Creators

/* ------------- Initial State ------------- */

export const INITIAL_STATE = Immutable({
  data: null,
  fetching: null,
  payload: null,
  error: null
})

/* ------------- Reducers ------------- */

// request the data from an api
export const request = (state, { data }) =>
  state.merge({ fetching: true,  payload: null })

// successful api lookup
export const success = (state, action) => {
  const { payload } = action
  return state.merge({ fetching: false, error: null, data })
}

// Something went wrong somewhere.
export const failure = state =>
  state.merge({ fetching: false, error })

/* ------------- Hookup Reducers To Types ------------- */

export const reducer = createReducer(INITIAL_STATE, {
  [Types.USERS_REQUEST]: request,
  [Types.USERS_SUCCESS]: success,
  [Types.USERS_FAILURE]: failure
})
来自Redux文件夹的

index.js:

import { combineReducers } from 'redux'
import configureStore from './CreateStore'
import rootSaga from '../Sagas/'

export default () => {
  /* ------------- Assemble The Reducers ------------- */
  const rootReducer = combineReducers({
    nav: require('./NavigationRedux').reducer,
    github: require('./GithubRedux').reducer,
    login: require('./LoginRedux').reducer,
    search: require('./SearchRedux').reducer,
    users: require('./UsersRedux').reducer
  })

  return configureStore(rootReducer, rootSaga)
}

UsersSagas.js:

/* ***********************************************************
* A short word on how to use this automagically generated file.
* We're often asked in the ignite gitter channel how to connect
* to a to a third party api, so we thought we'd demonstrate - but
* you should know you can use sagas for other flow control too.
*
* Other points:
*  - You'll need to add this saga to sagas/index.js
*  - This template uses the api declared in sagas/index.js, so
*    you'll need to define a constant in that file.
*************************************************************/

import { call, put } from 'redux-saga/effects'
import UsersActions from '../Redux/UsersRedux'

export function * getUsers (api, action) {
  const { data } = action
  // make the call to the api
  const response = yield call(api.getUsers, data)

  // success?
  if (response.ok) {
    // You might need to change the response here - do this with a 'transform',
    // located in ../Transforms/. Otherwise, just pass the data back from the api.
    yield put(UsersActions.usersSuccess(response.data))
  } else {
    yield put(UsersActions.usersFailure())
  }
}
来自Sagas的

index.js

import { takeLatest, all } from 'redux-saga/effects'
import API from '../Services/Api'
import FixtureAPI from '../Services/FixtureApi'
import DebugConfig from '../Config/DebugConfig'

/* ------------- Types ------------- */

import { StartupTypes } from '../Redux/StartupRedux'
import { GithubTypes } from '../Redux/GithubRedux'
import { LoginTypes } from '../Redux/LoginRedux'
import { UsersTypes } from "../Redux/UsersRedux";

/* ------------- Sagas ------------- */

import { startup } from './StartupSagas'
import { login } from './LoginSagas'
import { getUserAvatar } from './GithubSagas'
import { getUsers } from "./UsersSagas"

/* ------------- API ------------- */

// The API we use is only used from Sagas, so we create it here and pass along
// to the sagas which need it.
const api = DebugConfig.useFixtures ? FixtureAPI : API.create()

/* ------------- Connect Types To Sagas ------------- */

export default function * root () {
  yield all([
    // some sagas only receive an action
    takeLatest(StartupTypes.STARTUP, startup),
    takeLatest(LoginTypes.LOGIN_REQUEST, login),

    // some sagas receive extra parameters in addition to an action
    takeLatest(GithubTypes.USER_REQUEST, getUserAvatar, api),
    takeLatest(UsersTypes.USER_REQUEST, getUsers, api)
  ])
}

LoginScreen.js:

import React, { PropTypes } from "react";
import { View, ScrollView, Text, TextInput, TouchableOpacity, Image, Keyboard, LayoutAnimation } from "react-native";
import { connect } from "react-redux";
import Styles from "./Styles/LoginScreenStyles";
import { Images, Metrics } from "../Themes";
import LoginActions from "../Redux/LoginRedux";
import { Button, Text as NBText, Contant, Form, Item, Input, Label, StyleProvider } from "native-base";
import buttonTheme from '../../native-base-theme/components/';
import commonColor from '../../native-base-theme/variables/commonColor';
import UsersActions from "../Redux/UsersRedux";

class LoginScreen extends React.Component {
    static propTypes = {
        dispatch: PropTypes.func,
        fetching: PropTypes.bool,
        attemptLogin: PropTypes.func,
        getUsers: PropTypes.func
    };

    isAttempting = false;
    keyboardDidShowListener = {};
    keyboardDidHideListener = {};

    constructor(props) {
        super(props);
        this.props.getUsers();
        this.state = {
            username: "",
            password: "",
            visibleHeight: Metrics.screenHeight,
            topLogo: { width: Metrics.screenWidth - 40 },
        };
        this.isAttempting = false;
    }

    componentWillReceiveProps(newProps) {
        this.forceUpdate();
        // Did the login attempt complete?
        if (this.isAttempting && !newProps.fetching) {
            this.props.navigation.goBack();
        }
    }

    componentWillMount() {
        // Using keyboardWillShow/Hide looks 1,000 times better, but doesn't work on Android
        // TODO: Revisit this if Android begins to support - https://github.com/facebook/react-native/issues/3468
        this.keyboardDidShowListener = Keyboard.addListener("keyboardDidShow", this.keyboardDidShow);
        this.keyboardDidHideListener = Keyboard.addListener("keyboardDidHide", this.keyboardDidHide);
    }

    componentWillUnmount() {
        this.keyboardDidShowListener.remove();
        this.keyboardDidHideListener.remove();
    }

    keyboardDidShow = e => {
        // Animation types easeInEaseOut/linear/spring
        LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
        let newSize = Metrics.screenHeight - e.endCoordinates.height;
        this.setState({
            visibleHeight: newSize,
            topLogo: { width: 100, height: 70 },
        });
    };

    keyboardDidHide = e => {
        // Animation types easeInEaseOut/linear/spring
        LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
        this.setState({
            visibleHeight: Metrics.screenHeight - 100,
            topLogo: { width: Metrics.screenWidth - 40 },
        });
    };

    handlePressLogin = () => {
        // const { username, password } = this.state
        // this.isAttempting = true
        // attempt a login - a saga is listening to pick it up from here.
        // this.props.attemptLogin(username, password);
        this.props.navigation.navigate("LaunchScreen");
    };

    handlePressRegister = () => {
        // const { username, password } = this.state
        // this.isAttempting = true
        // attempt a login - a saga is listening to pick it up from here.
        // this.props.attemptLogin(username, password);
        this.props.navigation.navigate("RegisterScreen");
    };

    handleChangeUsername = text => {
        this.setState({ username: text });
    };

    handleChangePassword = text => {
        this.setState({ password: text });
    };

    render() {
        const { username, password } = this.state;
        const { fetching } = this.props;
        const editable = !fetching;
        const textInputStyle = editable ? Styles.textInput : Styles.textInputReadonly;
        return (
            <ScrollView
                contentContainerStyle={{ justifyContent: "center" }}
                style={[Styles.container, { height: this.state.visibleHeight }]}
                keyboardShouldPersistTaps="always"
            >
                <Image source={require("../Images/tuku_omah_logo_login.jpeg")} style={[Styles.topLogo, this.state.topLogo]} />
                <View style={Styles.form}>
                    <Form>
                        <Item stackedLabel>
                            <Label>Username</Label>
                            <Input
                                ref="username"
                                value={username}
                                editable={editable}
                                keyboardType="default"
                                returnKeyType="next"
                                autoCapitalize="none"
                                autoCorrect={false}
                                onChangeText={this.handleChangeUsername}
                                underlineColorAndroid="transparent"
                                onSubmitEditing={() => this.password._root.focus()}
                            />
                        </Item>
                        <Item stackedLabel>
                            <Label>Password</Label>
                            <Input
                                ref={ref => (this.password = ref)}
                                value={password}
                                editable={editable}
                                keyboardType="default"
                                returnKeyType="go"
                                autoCapitalize="none"
                                autoCorrect={false}
                                secureTextEntry
                                onChangeText={this.handleChangePassword}
                                underlineColorAndroid="transparent"
                                onSubmitEditing={this.handlePressLogin}
                            />
                        </Item>
                    </Form>
                    <View style={[Styles.loginRow]}>
                    <StyleProvider style={buttonTheme(commonColor)}>
                        <Button style={{ flex: 1, justifyContent: "center" }} full onPress={this.handlePressLogin}>
                            <NBText>Sign In</NBText>
                        </Button>
                    </StyleProvider>
                    </View>
                    <Text style={Styles.registerText} onPress={this.handlePressRegister}>
                        Tidak punya akun? Daftar di sini
                    </Text>
                </View>
            </ScrollView>
        );
    }
}

const mapStateToProps = state => {
    return {
        //fetching: state.login.fetching,
        users: state.users
    };
};

const mapDispatchToProps = dispatch => {
    return {
        //attemptLogin: (username, password) => dispatch(LoginActions.loginRequest(username, password)),
        getUsers: () => dispatch(UsersActions => dispatch(UsersActions.getUsers()))
    };
};

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

1 个答案:

答案 0 :(得分:1)

在usersRedux.js中,您可以定义UsersTypes。

其中一个是UsersTypes.USERS_REQUEST。

在sagas的index.js中,您尝试在UsersTypes.USER_REQUEST上运行您的用户传奇。

此操作类型值不存在,您在USERS_REQUEST中缺少S。

你传递给takeLatest以开始你的传奇的actionType在这种情况下被称为模式。