Maison >interface Web >js tutoriel >Pratique de la pile technologique React d'une petite application pour la collection de films

Pratique de la pile technologique React d'une petite application pour la collection de films

小云云
小云云original
2017-12-18 15:43:061505parcourir
Cet article partage principalement avec vous la pratique de la pile technologique React d'une petite application pour la collection de films, j'espère qu'il pourra vous aider.

Fonctions principales

  • Explorer les informations sur le film Douban et les saisir dans MongoDB

  • Affichage de la liste de films, classification, recherche

  • Affichage des détails du film et gestion des pièces jointes

  • Inscription et connexion

  • Contrôle des autorisations, les utilisateurs ordinaires peuvent se connecter dans, Favoris, saisie administrateur, modification, suppression

  • Centre utilisateur, ma liste de favoris

Pratique de la pile technologique React d'une petite application pour la collection de films

Quelques résumés

Front-end

Le front-end utilise React, Redux et Redux-saga Résumons brièvement Redux et enregistrons un problème de dépendance sur les appels d'interface avant et arrière.

  • redux

Pour résumer redux en une phrase, je pense que c'est pour emmêler le transfert d'accessoires verticaux entre les composants et l'amour-haine relation entre les composants parent et enfant. Elle est égalisée et une relation verticale est transformée en 多个组件和一个独立出来的状态对象直接交互, de sorte que la structure du code semble plus claire.

Les concepts fondamentaux de redux, d'action, de réducteur et de magasin

action就是说明我要操作一个状态了,怎么操作是reducer的事,而所有状态存储在store中,store发出动作并交由指定的reducer来处理

redux nous oblige à standardiser nos opérations sur l'état, ce qui ne peut être effectué que dans des actions et les réducteurs. De cette façon, le traitement logique métier complexe d'origine est modifié et limité aux actions et aux réducteurs, et les composants semblent très propres. En fait, c'est compliqué peu importe où mettre cette chose compliquée, mais maintenant c'est un peu plus clair

L'inconvénient d'utiliser redux est qu'il est trop fastidieux de définir diverses actions et de connecter différents composants. . . . . Maintenant, il y a un autre Mobx, je ne sais pas à quel point il est puissant, mais tout le monde est d'accord~

  • redux-saga

redux-saga est utilisé pour gérer les appels asynchrones et d'autres choses, utiliser des générateurs pour rendre le code asynchrone plus concis. Les plus couramment utilisés sont take,takeLatest,takeEvery,put,call,fork,select Au cours du processus d'utilisation, j'ai rencontré un problème de dépendances entre les appels d'interface. >

Décrivez-le :

  1. possède une interface

    /api/user/checkLogin, qui est utilisée pour déterminer s'il faut se connecter. Le composantDidMount du plus externe Composant Déclenchez une action pour lancer cette demande, et si l'état de retour de l'interface est connecté, vous devez également envoyer un

function* checkLogin() {
    const res = yield Util.fetch('/api/user/checkLogin')
    yield put(recieveCheckLogin(!res.code))
    if (!res.code) {
        //已登录
        yield put(fetchUinfo())
    }
}
export function* watchCheckLogin() {
    yield takeLatest(CHECK_LOAGIN, checkLogin)
}
  1. pour obtenir des informations sur l'utilisateur. Ensuite, j'ai un composant de page Détails du film, dans le

    componentDidMount de ce composant, l'interface /api/movies/${id} sera lancée pour obtenir des informations sur le film. . Si l'utilisateur est connecté, une interface permettant d'obtenir les informations sur les pièces jointes du film sera également lancée/api/movies/${id}/attach, L'étape entière est écrite dans un générateur

    <.>
function* getItemMovie(id) {
    return yield Util.fetch(`/api/movies/${id}`)
}

function* getMovieAttach(id) {
    return yield Util.fetch(`/api/movies/${id}/attach`)
}

function* getMovieInfo(action) {
    const { movieId } = action
    let { login } = yield select(state => state.loginStatus)
    const res = yield call(getItemMovie, movieId)
    yield put(recieveItemMovieInfo(res.data[0]))
    if (res.data[0].attachId && login) {
        const attach = yield call(getMovieAttach, movieId)
        yield put(recieveMovieAttach(attach.data[0]))
    }
}

export function* watchLoadItemMovie() {
    yield takeLatest(LOAD_ITEM_MOVIE, getMovieInfo)
}
    L'utilisateur est connecté et saisit les détails, le processus est normal, mais si la page est actualisée sur la page de détails, l'interface d'obtention des pièces jointes n'est pas déclenchée. la raison est que l'interface checkLogin n'a pas renvoyé le résultat pour le moment, le statut
  1. est toujours faux et ce qui précède ne va pas au if

    state.loginStatus

  2. Au début, je pensais sur la façon de contrôler la séquence de rendement dans certains générateurs pour résoudre le problème (si l'utilisateur n'est pas connecté, envoyez un autre CHECK_LOAGIN et le processus continuera après le retour du résultat), mais il y a des appels CHECK_LOAGIN deux fois si après la journalisation. dans, il y aura un appel d'interface supplémentaire pour obtenir des informations sur l'utilisateur, ce qui n'est certainement pas possible
function* getMovieInfo(action) {
    const { movieId } = action
    let { login } = yield select(state => state.loginStatus)
    const res = yield call(getItemMovie, movieId)
    yield put(recieveItemMovieInfo(res.data[0]))
    // if (!login) {
    //     //刷新页面的时候,如果此时checklogin接口还没返回数据或还没发出,应触发一个checklogin
    //     //checklogin返回后才能得到login状态
    //     yield put({
    //         type: CHECK_LOAGIN
    //     })
    //     const ret = yield take(RECIEVE_CHECK_LOAGIN)
    //     login = ret.loginStatus
    // }
    if (res.data[0].attachId && login) {
        const attach = yield call(getMovieAttach, movieId)
        yield put(recieveMovieAttach(attach.data[0]))
    }
}
    La méthode finale consiste à décomposer les responsabilités du générateur, composantWillUpdate Déclencher correctement l'action d'obtention des pièces jointes
//将获取附件的动作从 getMovieInfo这个generator中分离出来
function* getMovieInfo(action) {
    const { movieId } = action
    const res = yield call(getItemMovie, movieId)
    yield put(recieveItemMovieInfo(res.data[0]))
}
function* watchLoadItemMovie() {
    yield takeLatest(LOAD_ITEM_MOVIE, getMovieInfo)
}
function* watchLoadAttach() {
    while (true) {
        const { movieId } = yield take(LOAD_MOVIE_ATTACH)
        const { attachId } = yield select(state => state.detail.movieInfo)
        const attach = yield call(getMovieAttach, movieId)
        yield put(recieveMovieAttach(attach.data[0]))
    }
}

//组件中
componentWillUpdate(nextProps) {
        if (nextProps.loginStatus && (nextProps.movieInfo!==this.props.movieInfo)) {
            //是登录状态,并且movieInfo已经返回时
            const { id } = this.props.match.params
            this.props.loadMovieAttach(id)
        }
}
    En conclusion, utilisez la fonction hook du composant de manière rationnelle, et ne traitez pas trop d'opérations dans le générateur pour augmenter la flexibilité
  1. Backend

Le backend utilise express et mongodb, et redis est également utilisé. Les principaux points techniques sont

Pour activer l'identité. authentification dans mongodb, utilisez token+redis. Cela vaut la peine d'enregistrer lors de l'authentification d'identité et de l'écriture de tests unitaires dans node

使用pm2来管理node应用及部署代码

    Utilisez jwt + redis pour l'authentification d'identité d'utilisateur basée sur un jeton
  • Processus d'authentification basé sur des jetons

    Le client lance la demande de connexion
  1. Le serveur vérifie le nom d'utilisateur et le mot de passe
  2. Après une vérification réussie, le serveur génère un token et répond au client
  3. Le client portera ce token dans l'en-tête de chaque requête ultérieure
  4. Le serveur doit vérifier le jeton de l'interface qui nécessite une authentification et vérifier que la demande est reçue avec succès
  5. Ici, jsonwebtoken est utilisé pour générer le jeton ,

est utilisé avec un jeton de vérification express-jwt (une vérification réussie mettra les informations du jeton dans request.user)
jwt.sign(payload, secretOrPrivateKey, [options, callback])

Pourquoi utiliser redis
express_jwt({
        secret: SECRET,
        getToken: (req)=> {
        if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
            return req.headers.authorization.split(' ')[1];
        } else if (req.query && req.query.token) {
            return req.query.token;
        }
        return null;
    }
    }

** Lorsque vous utilisez jsonwebtoken pour générer un jeton, vous pouvez spécifier la période de validité du jeton, et la méthode de vérification de jsonwebtoken fournit également des options pour mettre à jour la période de validité du jeton
Mais le middleware express_jwt est utilisé ici. , et express_jwt ne fournit pas de méthode pour actualiser le jeton. **

Idée :

  1. Le client demande une connexion avec succès et génère un jeton

  2. Enregistrez ce token dans redis, définissez la période de validité de redis (par exemple, 1h)

  3. Lorsqu'une nouvelle demande arrive, vérifiez d'abord le token avec express_jwt, la vérification réussit, puis vérifiez si le jeton existe dans redis, la déclaration d'existence est valide

  4. Pendant la période de validité, une nouvelle demande vient du client, extrayez le jeton et mettez à jour le période de validité de ce token dans redis

  5. Le client se déconnecte de la demande de connexion et supprime ce token dans redis

Code spécifique

  • Utilisez mocha + supertest + Should pour écrire des tests unitaires

Couverture des tests J'ai écrit toutes les interfaces Pendant le développement, je les ai écrites lentement car il n'y en avait pas. exigences de progression. Après avoir écrit une interface, j'ai écrit un test. Une fois le test réussi, j'ai ensuite ajusté l'interface sur le front-end

mocha est un framework de tests unitaires de nœuds, similaire au jasmine frontal, avec une syntaxe similaire

supertest est une bibliothèque utilisée pour tester les interfaces de nœuds

Bibliothèque d'assertions nodejs, très lisible

Un exemple de test, c'est trop long, donc je ne le mettrai pas ici

Recommandations associées :

Explorer le mécanisme interne de React

Quelles sont les façons d'écrire des composants dans React

react.js donne la référence du logo , récupérez le contenu


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn