我是新的反应原生与点燃样板。我尝试使用API来创建用于登录检查用户数据的简单功能。但是,我收到错误:在登录时未捕获的最新内容ReferenceError:未定义调用。
这是我的代码: 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})
//Method for Backend-Server
//Users Methods
const getUsers = () => api.get('/users')
const login = (username, password) => api.post('users/login', {username: username, password: password})
// ------
// 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,
login
}
}
// let's return back our create method as the default.
export default {
create
}
LoginRedux.js:
import { createReducer, createActions } from 'reduxsauce'
import Immutable from 'seamless-immutable'
/* ------------- Types and Action Creators ------------- */
const { Types, Creators } = createActions({
loginRequest: ['username', 'password'],
loginSuccess: ['username'],
loginFailure: ['error'],
logout: null
})
export const LoginTypes = Types
export default Creators
/* ------------- Initial State ------------- */
export const INITIAL_STATE = Immutable({
username: null,
error: null,
payload: null,
fetching: false
})
/* ------------- Reducers ------------- */
// we're attempting to login
export const request = (state) => state.merge({ fetching: true, payload: null })
// we've successfully logged in
export const success = (state, { username }) =>
state.merge({ fetching: false, error: null, username })
// we've had a problem logging in
export const failure = (state, { error }) =>
state.merge({ fetching: false, error })
// we've logged out
export const logout = (state) => INITIAL_STATE
/* ------------- Hookup Reducers To Types ------------- */
export const reducer = createReducer(INITIAL_STATE, {
[Types.LOGIN_REQUEST]: request,
[Types.LOGIN_SUCCESS]: success,
[Types.LOGIN_FAILURE]: failure,
[Types.LOGOUT]: logout
})
/* ------------- Selectors ------------- */
// Is the current user logged in?
export const isLoggedIn = (loginState) => loginState.username !== null
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)
}
LoginSagas.js:
import { put } from 'redux-saga/effects'
import LoginActions from '../Redux/LoginRedux'
// attempts to login
export function * login (api, { username, password }) {
const response = yield call(api.login, username, password)
if(response.ok) {
// dispatch successful logins
yield put(LoginActions.loginSuccess(username))
} else {
yield put(LoginActions.loginFailure('WRONG'))
}
// if (password === '') {
// // dispatch failure
// yield put(LoginActions.loginFailure('WRONG'))
// } else {
// // dispatch successful logins
// yield put(LoginActions.loginSuccess(username))
// }
}
佐贺的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, api),
// some sagas receive extra parameters in addition to an action
takeLatest(GithubTypes.USER_REQUEST, getUserAvatar, api),
takeLatest(UsersTypes.USERS_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 } from "native-base";
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: "reactnative@infinite.red",
password: "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();
}
if(newProps.users!= null) {
console.log(newProps.users)
}
if(newProps.login != null) {
console.log("LOGIN TRY");
console.log(newProps.login);
}
if(newProps.fetching != null) {
console.log("LOGIN TRY 2");
console.log(newProps.fetching);
}
}
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,
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(this.state.username, this.state.password);
console.log("Try to login");
console.log(this.props.login);
this.props.navigation.navigate("LaunchScreen");
};
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={Images.logo} 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]}>
<Button style={{ flex: 1, justifyContent: "center" }} full onPress={this.handlePressLogin}>
<NBText>Sign In</NBText>
</Button>
<Button
style={{ flex: 1, justifyContent: "center" }}
full
onPress={() => this.props.navigation.goBack()}
>
<NBText>Cancel</NBText>
</Button>
</View>
</View>
</ScrollView>
);
}
}
const mapStateToProps = state => {
return {
fetching: state.login.fetching,
login: state.login,
users: state.users
};
};
const mapDispatchToProps = dispatch => {
return {
attemptLogin: (username, password) => dispatch(LoginActions.loginRequest(username, password)),
getUsers: () => dispatch(UsersActions.usersRequest())
};
};
export default connect(mapStateToProps, mapDispatchToProps)(LoginScreen);
请帮助谢谢。
答案 0 :(得分:0)
您需要import
call
才能使用
import {call, put} from 'redux-saga/effects'
,在 LoginSagas.js