質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.72%

React+Redux+Material-ui onClickイベントがiOSで反応しない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 198

khkhkh

score 10

前提・実現したいこと

現在、フロントエンドにReact+Redux+Material-ui、バックエンドにLaravelを使用してレスポンシブルなWebサイトを開発しています。また、Chromeの検証ツールでiOSの動作確認を行なっています。
そこで、onClickイベントが検証ツールではしっかり反応するのですが、自前のiPhone(7 plus)をローカルに繋いで、動作確認をしたところ、onClickイベントが反応しません。フロントエンドだけで完結するonClickに関しては動作しますが、バックエンドのLaravel APIと通信するonClickだけが反応しません。
一応、自分なりに調べて、iPhoneはタッチイベントというものがあるらしいので、該当要素にCSSでcusor:pointerとスタイルしてみましたが、解決せず…。
下記に、一例のJWTログイン処理のソースコードを記述しています。
iOSでは一応ボタンは反応している様な気がするのですが、ログインすることができません。PCでは可能です。
どなたか解決方法のご教授お願いいたします。

追記

恐らくonClickは反応しているのですが、Laravel APIとの非同期通信がうまくいってないです。
上述している様に検証ツールでは動くのですが、iOSでは動きません。

該当のソースコード

import React from 'react'
import { withStyles } from '@material-ui/core/styles'
import { Link } from 'react-router-dom'

import { Redirect } from "react-router-dom"

import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import * as actions from '../../actions'

import IconButton from '@material-ui/core/IconButton'
import CloseIcon from '@material-ui/icons/Close'
import Divider from '@material-ui/core/Divider'
import Button from '@material-ui/core/Button'
import Dialog from '@material-ui/core/Dialog'
import DialogContent from '@material-ui/core/DialogContent'
import DialogActions from '@material-ui/core/DialogActions'
import { DialogContentText } from '@material-ui/core'
import TextField from '@material-ui/core/TextField'
import CircularProgress from '@material-ui/core/CircularProgress'

const styles = () => ({
    root: {
        display: 'flex',
        justifyContent: 'center'
    },
    title: {
        display: 'flex',
        justifyContent: 'center',
        position: 'relative',
    },
    loginTitle: {
        marginTop: 20,
        marginBottom: 10,
        fontWeight: 'bold',
        fontSize: 20
    },
    close: {
        position: 'absolute',
        right: 3,
        color: 'gray'
    },
    input: {
        width: '100%',
        marginBottom: 20,
        fontSize: 15
    },
    loginButton: {
        width: 200,
        height: 50,
        margin: 'auto',
        marginTop: 10,
        marginBottom: 30,
        color: 'white',
        fontSize: 15,
        cursor: 'pointer' // 効果なし
    },
    signupTitle: {
        textAlign: 'center',
        marginTop: 20,
        marginBottom: 20,
        fontWeight: 'bold',
        fontSize: 20
    },
    signupText: {
        textAlign: 'center',
        fontSize: 10
    },
    signupButton: {
        width: 200,
        height: 50,
        margin: 'auto',
        marginBottom: 30,
        color: 'white',
        backgroundColor: '#bbb',
        fontSize: 15
    },
})

class LoginDialog extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            mail: '',
            pass: '',
        }
        this.handleOnChange = this.handleOnChange.bind(this)
        this.handleSubmit = this.handleSubmit.bind(this)
    }

    handleOnChange(e) {
        this.setState({
            [e.target.name]: e.target.value,
        })
    }

    handleSubmit() {
        const values = {
            email: this.state.mail,
            password: this.state.pass,
        }
        this.props.actions.loginUser(values, history)
    }

    render() {
        const { classes } = this.props

        const { LoginDialogReducer, AuthReducer, actions } = this.props

        return (
            AuthReducer.isAuthenticated && localStorage.getItem('token') ? (
                <Redirect to={'/'} />
            ) : (
                    <div className={classes.root}>
                        <Dialog
                            fullWidth={true}
                            open={LoginDialogReducer.loginDialogOpen}
                            onClose={actions.toggleLoginDialog}
                            aria-labelledby="alert-dialog-title"
                            aria-describedby="alert-dialog-description"
                            className={classes.content}
                        >
                            <div className={classes.title}>
                                <h6 className={classes.loginTitle}>
                                    ログイン
                                </h6>
                                <IconButton
                                    key="close"
                                    aria-label="Close"
                                    color="inherit"
                                    className={classes.close}
                                    onClick={actions.toggleLoginDialog}
                                >
                                    <CloseIcon className={classes.icon} />
                                </IconButton>
                            </div>
                            <DialogContent>
                                <TextField
                                    required
                                    label="名前"
                                    name="mail"
                                    className={classes.input}
                                    onChange={e => this.handleOnChange(e)}
                                    variant="outlined"
                                />
                                <TextField
                                    required
                                    type="password"
                                    label="パスワード"
                                    name="pass"
                                    className={classes.input}
                                    onChange={e => this.handleOnChange(e)}
                                    variant="outlined"
                                />
                            </DialogContent>
                                <Button onClick={this.handleSubmit} variant="contained" color="primary" className={classes.loginButton}>
                                    {this.props.AuthReducer.isRequesting ? <CircularProgress /> : 'ログイン'}
                                </Button>
                            <Divider variant="middle" />
                            <DialogContent>
                                <h6 className={classes.signupTitle}>
                                    初めてのお客様
                                </h6>
                                <DialogContentText className={classes.signupText}>
                                    サービスを最大限利用するには会員登録が必要です
                        </DialogContentText>
                            </DialogContent>
                            <DialogActions>
                                <Button component={Link} to="/signup" onClick={actions.toggleLoginDialog} variant="contained" className={classes.signupButton}>
                                    新規会員登録
                                </Button>
                            </DialogActions>
                        </Dialog>
                    </div>
                )
        )
    }
}

const mapStateToProps = state => ({
    LoginDialogReducer: state.LoginDialogReducer,
    AuthReducer: state.AuthReducer
})

const mapDispatchToProps = dispatch => ({
    actions: bindActionCreators(actions, dispatch) // Actionを自動的にマッピング
})

const StyledLoginDialog = withStyles(styles, { withTheme: true })(LoginDialog)

export default connect(mapStateToProps, mapDispatchToProps)(StyledLoginDialog)
// Jwt login
export function loginUser({ email, password }) {
  return async (dispatch) => {  // 非同期処理
    try {
      // {hoge}でhoge:fugaと値が取れる
      dispatch({ type: actionTypes.AUTH_REQUEST })
      const res = await axios.post(`${URL}/login`, { email, password })
      const datalist = {
        'access_token': res.data.access_token,
        'expiration_date': res.data.expiration_date
      }
      localStorage.setItem('token', JSON.stringify(datalist))
      localStorage.setItem('name', JSON.stringify(res.data.name))
      dispatch({ type: actionTypes.LOGIN_SUCCESS })
    } catch (error) {
      console.log(error)
      dispatch({ type: actionTypes.AUTH_FAILURE, })
    }
  }
}
import * as actionTypes from '../utils/actionTypes'

const initialState = {
    loginDialogOpen: false,
}

const LoginDialogReducer = (state = initialState, action) => {
    switch (action.type) {
        case actionTypes.TOGGLE_LOGIN_DIALOG:
            return Object.assign({}, state, {
                loginDialogOpen: !state.loginDialogOpen
            })
        default:
            return state
    }
}

export default LoginDialogReducer

試したこと

該当要素にCSSでcusor:pointerとスタイル

補足情報(FW/ツールのバージョンなど)

Laravel 5.8.*

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

ipアドレスを変更したら解決いたしました!ご迷惑をおかけしました!

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.72%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる