私は疑問に思っていました...redux-observableでajaxの代わりにfetchまたはaws-amplify Auth.sigInを使用するにはどうすればよいですか?
以下の create-react-app ベースのコードを実行すると、次のエラーが発生します。
TypeError: __WEBPACK_IMPORTED_MODULE_2_rxjs__.a.from is not a function
私が現在拡張しているアプリは、次のパッケージと redux アプローチを使用しています。
パッケージ.json
...
"redux": "^4.0.0-rc.1",
"redux-observable": "^1.0.0-beta.1",
"rxjs": "^6.2.0",
"rxjs-compat": "^6.2.0",
"styled-components": "^3.3.2"
...
types.js
export default {
LOGIN_REQUEST: 'LOGIN_REQUEST',
LOGIN_SUCCESS: 'LOGIN_SUCCESS',
LOGIN_FAILURE: 'LOGIN_FAILURE',
};
アクション.js
import Types from './types';
export const loginRequest = (payload) => ({
type: Types.LOGIN_REQUEST,
payload,
});
export const loginSuccess = (payload) => ({
type: Types.LOGIN_SUCCESS,
payload,
});
export const loginFailure = (payload) => ({
type: Types.LOGIN_FAILURE,
payload,
});
epics.js
import { ajax } from 'rxjs/observable/dom/ajax';
import { ofType } from 'redux-observable';
import { Observable, from } from 'rxjs';
import { catchError, mergeMap, switchMap, map } from 'rxjs/operators';
import { Auth } from 'aws-amplify';
import Types from './types';
const loginSuccess = payload => ({
type: Types.LOGIN_SUCCESS,
payload,
});
const loginFailure = payload => ({
type: Types.LOGIN_FAILURE,
payload,
});
const api = {
signIn: (username, password) => {
const request = Auth.signIn(username, password)
.then(user => user.json())
.catch(err => err);
return Observable.from(request);
}
};
const loginRequest = (action$, state$) =>
action$.pipe(
ofType(Types.LOGIN_REQUEST),
mergeMap(action => {
console.log('===> Epic - action.payload', action.payload);
// This returns our Observable wrapping the Promise.
return api.signIn(action.payload.username, action.payload.password)
.map(payload => ({ type: Types.LOGIN_SUCCESS, payload }))
.catchError(payload => ({ type: Types.LOGIN_FAILURE, payload }))
})
);
export default loginRequest;
Signin.js
import React, { Component } from 'react';
import { bindActionCreators, compose } from 'redux';
import { connect } from 'react-redux';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import { Auth } from 'aws-amplify';
import { withStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton';
import Input from '@material-ui/core/Input';
import InputLabel from '@material-ui/core/InputLabel';
import InputAdornment from '@material-ui/core/InputAdornment';
import FormHelperText from '@material-ui/core/FormHelperText';
import FormControl from '@material-ui/core/FormControl';
import TextField from '@material-ui/core/TextField';
import Visibility from '@material-ui/icons/Visibility';
import VisibilityOff from '@material-ui/icons/VisibilityOff';
import { loginRequest } from './redux/actions';
const styles = theme => ({
root: {
display: 'flex',
flexWrap: 'wrap',
},
margin: {
margin: theme.spacing.unit,
},
withoutLabel: {
marginTop: theme.spacing.unit * 3,
},
textField: {
flexBasis: 200,
},
});
class SignIn extends Component {
static propTypes = {
auth: PropTypes.object,
classes: PropTypes.object,
data: PropTypes.array,
isLoading: PropTypes.bool,
loginRequest: PropTypes.func,
}
handleChange = prop => event => {
this.setState({ [prop]: event.target.value });
}
handleMouseDownPassword = event => {
event.preventDefault();
}
handleClickShowPassword = () => {
this.setState({ showPassword: !this.state.showPassword });
}
handleSubmit = event => {
event.preventDefault();
console.log('handleSubmit - this.state', this.state);
const payload = {
username: this.state.username,
pasword: this.state.password,
}
console.log('handleSubmit - payload', payload);
this.props.loginRequest(payload);
}
state = {
username: '',
password: '',
showPassword: false,
}
render() {
const {
auth,
classes,
data,
isLoading,
} = this.props
return(
<form
noValidate
autoComplete="off"
onSubmit={(e) => { this.handleSubmit(e) } }
>
<TextField
id="username"
label="Username"
onChange={this.handleChange('username')}
value={this.state.username}
margin="normal"
/>
<FormControl className={classNames(classes.margin, classes.textField)}>
<InputLabel htmlFor="password">Password</InputLabel>
<Input
id="password"
type={this.state.showPassword ? 'text' : 'password'}
value={this.state.password}
onChange={this.handleChange('password')}
endAdornment={
<InputAdornment position="end">
<IconButton
onClick={this.handleClickShowPassword}
onMouseDown={this.handleMouseDownPassword}
>
{this.state.showPassword ? <VisibilityOff /> : <Visibility />}
</IconButton>
</InputAdornment>
}
/>
</FormControl>
<Button
variant="contained"
color="primary"
type="submit"
label="Submit"
className={classes.button}
>
Login
</Button>
</form>
)
}
}
const mapDispatchToProps = dispatch => (
bindActionCreators({ loginRequest }, dispatch)
);
const mapStateToProps = state => ({
auth: state.auth,
data: state.user.data,
isLoading: state.user.isLoading,
});
export default compose(withStyles(styles, { name: 'SignIn' }), connect(mapStateToProps, mapDispatchToProps))(SignIn);
役立つリソース:
https://medium.com/dailyjs/using-redux-observable-to-handle-asynchronous-logic-in-redux-d49194742522
ありがとう!