Project Fake Search 3-1サーバのページ機能の実装と設定(サイト名とテーマ色、クエリーの自動完了)
52121 ワード
開始します。
牧業ページが完成し,まず検索ページ設定以外の設定機能の実現を開始する.ユーザ情報をデータベースに格納する部分は,一度に実現すると便利であるため,Sequelizeの移行や会員加入に関するAPIのように,まずサーバに必要な部分を実現する.
サーバ実装
Sequeizeの設定
//migrations/AutoCompletes
'use strict';
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('AutoCompletes', {
...
userId: {
type: Sequelize.INTEGER,
onDelete: 'CASCADE',
references:{model: 'Users', key: 'id'}
},
...
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('AutoCompletes');
}
};
//models/AutoCompletes
'use strict';
const {
Model
} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class AutoComplete extends Model {
...
static associate(models) {
AutoComplete.belongsTo(models.User,{
foreignKey: "userId",
onDelete: "CASCADE",
})
...
};
以前のプロジェクトでは、Sequelizeで多くのエラーが発生したため(https://github.com/codestates/Shall-We-Health/projects/3)、本プロジェクトではすべてのエラーの解決方法を見つけ、必要なクエリー文をまとめ、Raw Queryがなく、Sequelizeメソッドのみですべての機能を実現できると考えた.ただし、Sequeizeはバックエンドチームメンバーが担当しているため、CASCADE
に関する設定を行うには迷いましたが、modelsもmigrationsもonDelete: 'CASCADE'
の設定が必要であることを知り変更しました.訪問者のログアウトと会員の脱退時のユーザー.idを外部キーとするテーブルのデータも自動的に削除する必要があるため,外部キーを設定するとともにカスケード設定を行った.
ソーシャル・ログインの実施(NAVER)
//네이버 로그인 요청
const jwt = require("jsonwebtoken");
const { User } = require("../../models/index");
const axios = require("axios");
module.exports = async (req, res) => {
const { token } = req.body;
if (!token) {
return res.status(400).json({
data: null,
error: {
path: "users/naver",
message: "Insufficient body data",
},
});
}
const userData = await axios.get("https://openapi.naver.com/v1/nid/me", {
headers: {
Authorization: `Bearer ${token}`,
},
});
const identification = userData.data.response.id;
try {
const [user, created] = await User.findOrCreate({
where: { identification },
defaults: {
oauth: 'naver',
siteName: 'FAKESEARCH',
themeColor:'#2260FF',
},
});
if (!created) {
/* 회원가입이 되어있을 때 */
const accessToken = jwt.sign(
user.dataValues,
process.env.ACCESS_SECRET,
{ expiresIn: "7d" }
);
res
.cookie("accessToken", accessToken)
.status(200)
.end();
} else {
/* 회원가입 되어 있지 않을 때 */
const accessToken = jwt.sign(
user.dataValues,
process.env.ACCESS_SECRET,
{ expiresIn: "7d" }
);
res
.cookie("accessToken", accessToken)
.status(201)
.end();
}
} catch (err) {
...
};
設定機能を実現するためには、ユーザのデータを格納する必要があるため、NAVER登録から実現する.クライアントがNaverに要求して受信したtokenをサーバに転送すると、サーバはNaverにユーザ情報を受信し、findOrCreate
メソッドを使用してユーザ情報を問合せたり、再挿入したりしてaccessTokenをCookieに入れて応答します.以前のプロジェクトではKACAとNAVEROAuthの登録が実現していたので、スピーディーに進んでいました.セキュリティ上の理由により、naverログインはサーバ環境でのみユーザー情報を要求できますが、KACAとGoogleはクライアントで直接ユーザー情報を伝達するので、中間のaxoisリクエストを除いて同じ論理で実現します.
設定機能の実装
サイト名とトピックの色の設定
//checkSiteName.js
export default function checkSiteName(siteName) {
const name = siteName
const checkForm = new RegExp(/^[가-힣a-zA-Z]{2,10}$/);
const checkDomain = ['naver','daum','kakao','google','nate','네이버','다음','카카오','구글','네이트']
if(!checkForm.test(name) || name === null || checkDomain.some((el) => name.toLowerCase().includes(el))) {
return false
} else return true
}
Webサイト名を変更する機能は簡単な論理ですが、Webサイト名をチェックする関数も作成されています.ハングル、英語の2〜10文字しか含まれておらず、悪用される可能性があるため、有名ポータルサイト名を含まない単語に設定した.//사이트 이름 및 테마 색상 설정
import React, { useState, useEffect, useRef } from 'react';
import Color from './Color';
...
export default function Site() {
const { themeColor, siteName } = useSelector((state) => state.loginReducer)
const btnColor = useRef()
const boxColor = useRef()
const [modalColor, setModalColor] = useState(false)
...
const handleClickOutside = ({ target }) => {
if (!boxColor.current.contains(target) && !btnColor.current.contains(target)) setModalColor(false);
};
const handleCheck = (e) => {
setNicknameForm(e.target.value)
if(e.target.value==='') {
setIsChecked(true)
} else {
setIsChecked(checkSiteName(e.target.value))
}
}
...
useEffect(() => {
window.addEventListener("click", handleClickOutside);
return () => {
window.removeEventListener("click", handleClickOutside);
};
}, []);
return (
<div className='site-container'>
...
<div className='box-theme'>
<div className='title-theme'>테마 색상</div>
<div className='info-color' ref={btnColor}>
<div id='sample-color' style={{backgroundColor: themeColor}} onClick={()=>{setModalColor(!modalColor)}}/>
<div id='text-color' onClick={()=>{setModalColor(!modalColor)}}>{themeColor}</div>
</div>
<Color boxColor={boxColor} modalColor={modalColor} themeColor={themeColor}/>
</div>
</div>
)
}
トピックカラー適用セクションではreact-colorライブラリを使用し、useref設定を使用してカラーまたはカラーコードをクリックしたときに設定ウィンドウを表示し、外部をクリックしたときに閉じます.//Color.js
...
export default function Color({boxColor, modalColor }) {
const dispatch = useDispatch();
const { themeColor } = useSelector((state) => state.loginReducer)
const hadleThemeColor = (e) => {
axios.patch(`${process.env.REACT_APP_SERVER_API}/users/theme-color`, {
themeColor : e.hex
},{withCredentials: true})
.then (()=>{
dispatch(login({themeColor : e.hex}))
})
}
return <div ref={boxColor} className={modalColor ? 'color-container' : 'hidden'}>
<ChromePicker color={themeColor} onChange={hadleThemeColor}/>
</div>;
}
上記のコードは、色変更時にサーバに色コードを送信受信し、Reducerに値を変更した部分で、最初はマニュアルのthemeColor : e
のように書かれていましたが、エラーが発生しました.console.log(e)
であることを確認すると、e
自体は色コード値ではなく、複数の値を持つオブジェクトであるため、伝達に必要なハースコードに変更された.自動補完クエリーの設定
//Main.js
import React, { useState, useEffect, useRef } from 'react';
import filterAutoComplete from '../utils/filterAutoComplete';
...
export default function Main() {
...
const [searchWord, setSearchWord] = useState('');
const [autoComplete, setAutoComplete] = useState([]);
const [focus, setFocus] = useState(false);
const [modal, setModal] = useState(false);
...
const handleSeachWord = async (e) => {
setSearchWord(e.target.value);
if (
filterAutoComplete(e.target.value) !== '' &&
e.target.value.replace(/(\s*)/g, '') !== '' &&
isLogin
) {
const word = filterAutoComplete(e.target.value);
const res = await axios.get(
`${process.env.REACT_APP_SERVER_API}/auto/filtered`,
{ params: { word }, withCredentials: true }
);
setAutoComplete(res.data);
}
if (filterAutoComplete(e.target.value).replace(/(\s*)/g, '') === '') {
setAutoComplete([]);
}
};
return (
<div className='main-container'>
...
<div className='searchForm-container'>
...
<input
type='text'
className='search'
onChange={handleSeachWord}
onFocus={() => {
setFocus(true);
}}
onBlur={() => {
setFocus(false);
}}
onKeyPress={(e) => {
if (e.key === 'Enter') {
window.location.replace(`/search/query=${searchWord}`);
}
}}
></input>
...
{!(searchWord === '' && autoComplete.length === 0) && focus &&
autoComplete.map((el, id) => {
return (
<AutoList
key={id}
el={el}
searchWord={searchWord}
themeColor={themeColor}
></AutoList>
);
})}
...
</div>
</div>
);
}
//filterAutoComplete.js
export default function filterAutoComplete(autoWord) {
return autoWord.replace(/[^가-힣a-zA-Z0-9~!@#$%^&*()_+|<>?:{};\-=`.,/ ]+/g,'')
}
自動完了検索語を追加・削除する機能は簡単ですが、実際に検索ウィンドウで見た部分には思いがけないエラーがあるので条件を追加しました.自動完了検索語가, 가나, 가나다
この3つの語があれば가ㄴ
のように子音だけ入力しても自動完了検索語は가, 가나, 가나다
に表示されるべきで、inputウィンドウでフォーカスを外すと自動完了単語リストが見えなくなるようにfilterAutoComplete関数と複数のstateを作成して条件掛けを行います.の最後の部分
今回のプロジェクトでは、reactをより深く理解し、エラーを処理し、機能に必要な論理を考え出す過程に意味があると思います.新しいスキルを学ぶのもいいですが、以前使っていたスタックを深く理解する必要があります.さまざまなスタックを体験し、使いこなすことが望ましいが、新しい開発者として基礎を固めることが重要らしい.
Reference
この問題について(Project Fake Search 3-1サーバのページ機能の実装と設定(サイト名とテーマ色、クエリーの自動完了)), 我々は、より多くの情報をここで見つけました https://velog.io/@bbaa3218/Project-Fake-Search-3-1-서버-구현-및-설정-페이지-기능구현사이트-이름-및-테마-색상-자동완성-검색어テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol