이 글은 주로 영화 컬렉션을 위한 소규모 애플리케이션의 리액트 기술 스택 실습을 공유하는데, 도움이 되기를 바랍니다.
두반 영화 정보를 크롤링하여 MongoDB에 입력
영화 목록 표시, 분류, 검색
영화 세부 정보 표시 및 첨부 파일 관리
등록, 로그인
권한 control, 일반 사용자는 입력, 수집, 관리자 입력, 수정, 삭제 가능
사용자 센터, 즐겨찾기 목록
프론트 엔드는 React를 사용합니다. redux plus redux- saga, redux에 대한 간략한 요약, 전면 인터페이스 호출과 후면 인터페이스 호출 간의 종속성 문제 기록
redux를 한 문장으로 요약하자면 컴포넌트와 컴포넌트 사이의 수직 prop을 옮기는 것이라고 생각합니다. 상위 및 하위 구성 요소 간 상태의 애증 얽힘이 완화되었으며 수직 관계가 독립적인 상태 개체와 직접 상호 작용하는 여러 구성 요소
로 변환되었습니다. 더 명확해졌습니다. 多个组件和一个独立出来的状态对象直接交互
,这样之后,代码结构确实看上去更加清晰了。
redux的核心概念,action,reducer,和store
action就是说明我要操作一个状态了,怎么操作是reducer的事,而所有状态存储在store中,store发出动作并交由指定的reducer来处理
redux强制规范了我们对状态的操作,只能在action和reducer这些东西中,这样,原本错综复杂的业务逻辑处理就换了个地,限制在了action和reducer中,组件看上去就很干净了。其实,该复杂的东西在哪放都复杂,只不过现在更清晰一点
使用redux不好的地方就是太繁琐了,定义各种action,connect各种组件。。。。。现在又出来一个Mobx,不明觉厉,反正大家都说好~
redux-saga用来处理异步调用啥的,借助于generator,让异步代码看起来更简洁,常用的有take,takeLatest,takeEvery,put,call,fork,select
,使用过程中遇到一个接口调用有前后依赖关系的问题,比较有意思
描述一下:
有一个接口/api/user/checkLogin,用来判断是否登录,在最外层的
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) }
然后我有一个电影详情页组件,在这个组件的componentDidMount中会发起/api/movies/${id}
接口获取电影信息,如果用户是登录状态的话,还会发起一个获取电影附件信息的接口/api/movies/${id}/attach
,整个步骤写在一个generator中
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) }
用户登录了,进到详情,流程正常,但如果在详情页刷新了页面,获取附件的接口没触发,原因是此时checkLogin接口还没返回结果,state.loginStatus
状态还是false,上面就没走到if中
一开始想着怎么控制一些generator中yield的先后顺序来解决(如果用户没有登录的话,再发一个CHECK_LOAGIN,结果返回了流程再继续),但存在CHECK_LOAGIN调用两次,如果登录了,还会再多一次获取用户信息的接口调用的情况,肯定不行
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])) } }
最终的办法,分解generator的职责,componentWillUpdate中合适的触发获取附件的动作
//将获取附件的动作从 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) } }
总结,合理使用组件的钩子函数,generator中不要处理太多操作,增加灵活性
后端采用express和mongodb,也用到了redis,主要技术点有使用pm2来管理node应用及部署代码
액션은 스테이트를 운영하고 싶다는 뜻인데, 리듀서의 업무를 어떻게 운영할지가 스토어에 저장된다. 그리고 이를 지정된 리듀서에 넘겨 처리합니다.
redux는 액션과 리듀서에서만 수행할 수 있는 작업을 상태에서 표준화하도록 강제합니다. 이러한 방식으로 원래 복잡했던 비즈니스 로직 처리가 변경되고 액션과 리듀서로 제한되어 있어 컴포넌트가 매우 깨끗해 보입니다. 사실 이 복잡한 것을 어디에 넣어도 복잡하지만 이제는 조금 더 명확해졌습니다take, takeLatest, takeEvery, put, call, fork, select
입니다. 사용 중에 인터페이스 호출의 종속성에 문제가 발생했습니다. 설명해보세요:
jwt.sign(payload, secretOrPrivateKey, [options, callback])
comComponentDidMount >/api/movies/${id}
인터페이스에서 시작됩니다. 에서는 영화 첨부 정보를 얻기 위한 인터페이스도 /api/movies /${id}/attach
로 시작됩니다. 전체 단계는 생성기에 기록됩니다.
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; } }
state.loginStatus
상태는 여전히 false이고 위의 내용은 if
로 이동하지 않습니다. 처음에는 어떻게 해야할지 생각했습니다. 문제를 해결하기 위해 일부 생성기의 수율 순서를 제어하지만(사용자가 로그인하지 않은 경우 다른 CHECK_LOAGIN을 보내면 프로세스가 계속 진행됨) 사용자가 로그인한 경우 CHECK_LOAGIN에 대한 두 번의 호출이 있습니다. 사용자 정보를 한 번에 얻기 위해 인터페이스를 호출하는 것은 확실히 불가능합니다🎜rrreee🎜🎜🎜마지막 방법은 생성자의 책임을 분해하고 컴포넌트WillUpdate에서 첨부 파일을 얻는 작업을 적절하게 트리거하는 것입니다🎜🎜 🎜rrreee🎜🎜🎜결론적으로 컴포넌트를 합리적으로 사용 Hook 기능, 생성기에서 너무 많은 연산을 처리하지 않고 유연성을 높인다🎜🎜🎜🎜Backend🎜🎜 백엔드는 express와 mongodb를 사용하며, redis도 사용하는 것이 주요 기술 포인트입니다. pm2를 사용하여 노드 애플리케이션 관리 및 코드 배포
, mongodb에서 신원 인증 활성화, 신원 인증을 위해 토큰+redis 사용, 노드에서 단위 테스트 작성, 기록할 가치가 있습니다🎜🎜🎜🎜jwt + redis 사용 토큰 기반 사용자 신원 인증을 위해 🎜🎜🎜🎜토큰 기반 인증 프로세스🎜🎜🎜🎜클라이언트가 로그인 요청을 시작합니다🎜🎜🎜🎜서버가 사용자 이름과 비밀번호를 확인합니다🎜🎜🎜🎜확인에 성공하면 서버는 다음을 생성합니다. 토큰을 생성하고 클라이언트🎜🎜🎜🎜Client에 응답합니다. 각 후속 요청 헤더는 이 토큰을 가져옵니다🎜🎜🎜🎜서버는 인증이 필요한 인터페이스에 대한 토큰을 확인해야 하며, 확인을 통해 요청이 성공적으로 수신됩니다🎜🎜🎜🎜여기 jsonwebtoken은 토큰을 생성하는 데 사용됩니다.🎜rrreee🎜확인 토큰에는 express-jwt를 사용합니다(성공적인 확인은 request.user에 토큰 정보를 입력합니다)🎜rrreee🎜redis를 사용하는 이유🎜**jsonwebtoken을 사용하여 토큰을 생성할 때 토큰의 유효 기간을 지정할 수 있으며 jsonwebtoken의 verify 메서드도 토큰의 유효 기간을 업데이트하는 옵션을 제공합니다.
그러나 여기서는 express_jwt 미들웨어가 사용되며 express_jwt는 이를 수행합니다. 토큰을 새로 고치는 방법을 제공하지 않음**
아이디어:
클라이언트가 로그인을 성공적으로 요청하고 토큰을 생성합니다
이 토큰을 Redis에 저장하고 Redis의 유효 기간을 설정합니다(예: 1시간)
새 요청이 오면 먼저 express_jwt가 토큰을 검증하고 검증에 성공한 다음, 해당 토큰이 Redis에 존재하는지 검증합니다.
클라이언트가 유효 기간 동안 새 요청을 하고 추출합니다. 토큰을 업데이트하고 redis
이 토큰의 유효 기간을 업데이트합니다. 클라이언트는 로그인 요청을 종료하고 redis에서 삭제합니다. 이 토큰의 특정 코드
mocha + supertest + should를 사용하여 단위 테스트를 작성합니다
supertest는 노드 인터페이스를 테스트하는 데 사용되는 라이브러리입니다
읽기 쉬운 nodejs 어설션 라이브러리
테스트의 예, 너무 길기 때문에 여기에 넣지 않겠습니다관련 권장 사항:
React의 내부 메커니즘 탐색방법은 무엇입니까? React에서 컴포넌트를 작성하려면?
위 내용은 영화 컬렉션을 위한 소규모 애플리케이션의 React 기술 스택 실습의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!