오늘은 11월 23일 23일차이다.
드디어 가닥이 잡혔다. 어제 발생했던 오류는 array 메서드를 잘 못 써서 발생한 것이였다. 단어를 입력하면 나는 wordList.splice()를 통해 wordList를 업데이트해줬는데, wordList.splice는 반환값으로 교체한 대상을 담은 배열을 반환하기 때문에 입력한 단어를 제외한 모든 단어를 지워버렸다. 그래서 이 부분을 ... 구문으로 수정했다.
useEffect(() => { // 렌더링될 때
connectSocket(params.maker);
client.get(`/solve/${params.maker}`)
.then( res => {
if ( res.data === 'no-session')
setMessage('Enter your nickname!');
else {
nickname = res.data.nickname;
setLineSet(sixLines);
setWordCorrect(res.data.wordCorrect);
keyState = res.data.keyState;
submitNickname = true;
setTimeout(() => {
setWordList(res.data.wordList);
setListIndex(res.data.listIndex);
console.log("res.wordList", res.data.wordList);
setWord(res.data.lastWord);
console.log("res.lastWord:", res.data.lastWord);
}, 100);
}
})
}, [params]);
우선 solverPage에서 처음 렌더링될 때 실행되는 부분이다. 세션이 여부를 판단하고 없으면 데이터를 받는데, wordList, listIndex, lastWord를 받아 업데이트해준다.
router.get('/:maker', async (req, res) => {
try {
console.log(req.session);
if ( req.session.solver === undefined || !req.session.solver[req.params.maker] ) {
res.send('no-session');
return;
}
const maker = await Maker.findOne({
attributes: ['correct_word'],
where: {
nickname: req.params.maker,
},
include: [{
model: Solver,
attributes: ['word_list', 'key_state'],
where: {
nickname: req.session.solver[req.params.maker],
}
}],
});
let word_list = maker.Solvers[0].word_list;
let key_state = maker.Solvers[0].key_state;
word_list = JSON.parse(word_list);
key_state = JSON.parse(key_state);
if ( word_list === null )
word_list = [[]];
if ( key_state === null )
key_state = {};
let last_word, listIndex;
console.log("word_list", word_list);
console.log("word_list.length:", word_list.length);
console.log("element:", word_list[word_list.length - 1]);
if ( word_list[word_list.length - 1].length === 0) {
listIndex = word_list.length - 1;
last_word = [];
}
else if ( word_list[word_list.length - 1][0].state === 'filled' ) {
listIndex = word_list.length - 1;
last_word = word_list[word_list.length - 1];
}
else {
listIndex = word_list.length;
last_word = [];
}
console.log("last_word:", last_word);
console.log("correct_word:", maker.correct_word, "word_list", word_list);
res.send({
wordCorrect: maker.correct_word,
wordList: word_list,
keyState: key_state,
lastWord: last_word,
nickname: req.session.solver[req.params.maker],
listIndex: listIndex,
});
} catch (error) {
console.error(error);
}
});
이 부분은 GET /solve/:maker 요청을 처리하는 라우터이다. db로부터 해당 word_list를 뽑아낸 후, word_list의 상태에 따라 listIndex와 last_word를 결정해준다. word_list의 마지막 요소가 빈 배열이라면, 여기서부터 입력을 시작해야하므로 listIndex는 마지막 인덱스, last_word는 빈 배열로 설정한다. 마지막 요소가 filled 상태라면, 여기서부터 입력을 시작해야하므로 listIndex는 마지막 인덱스, last_word는 마지막 요소로 설장한다. 그외의 경우에는 word_list의 마지막 인덱스까지 다 차있다는 말이므로 listIndex를 마지막 인덱스 다음부터, last_word는 빈 배열로 설정한다.
useEffect(() => {
if ( submitNickname ) {
console.log('wordlist:', wordList);
console.log('listIndex:',listIndex);
if ( wordList[listIndex] === undefined ) {
setWordList([
...wordList,
word
]);
} else {
setWordList(wordList.map((element, index) => {
if ( index === listIndex )
return word;
else
return element;
}));
}
client.post(`/solve/${params.maker}/typing`, { newWord: word, listIndex: listIndex }) // 입력한 단어 및 키 상태 서버에 등록
.catch(error => {
console.log(error);
})
}
}, [word, params]);
이 부분이 핵심인데, word가 바뀔 때마다, 즉 문자를 입력할 때마다 실행되는 부분이다. 만약 해당 인덱스에 요소가 없다면 word를 새로 wordList에 넣어주고, 아니라면 map 함수를 통해 해당 인덱스만 바꿔준다. 이후 서버에 POST /solve/:maker/typing 요청을 보낸다.
router.post('/:maker/typing', async (req, res) => {
// solver 테이블에 등록
const solver = await Solver.findOne({
attributes: ['word_list'],
where: {
nickname: req.session.solver[req.params.maker],
maker: req.params.maker,
}
});
let word_list = JSON.parse(solver.word_list);
console.log(req.body.newWord, req.body.listIndex);
if ( word_list === null )
word_list = [];
console.log(word_list.length);
if ( word_list.length === req.body.listIndex )
word_list.push(req.body.newWord);
else if ( word_list.length > req.body.listIndex)
word_list.splice(req.body.listIndex, 1, req.body.newWord);
word_list = JSON.stringify(word_list);
await Solver.update({
word_list: word_list,
}, {
where: {
nickname: req.session.solver[req.params.maker],
maker: req.params.maker,
}
});
req.app.get('io').of('/loader').to(req.params.maker).emit('enter', await getSolvers(req.params.maker));
console.log(word_list);
res.end();
});
POST /solve/:maker/typing 요청을 처리하는 라우터이다. solver 테이블에서 word_list를 뽑아주고, listIndex와 word_list의 상태에 따라 push나 splice를 해준다. 이후 req.app.get('io')~ 로 시작하는 부분은 웹소켓을 통해 solvers 데이터를 전송하는 부분이다.
드디어 문자 단위 웹소켓이 제대로 작동한다. 5일차동안 시간을 여기에만 썼는데, 이제야 되서 다행이라는 생각이 든다. 동시에 나는 아직도 많이 부족하구나라는 생각도 든다. 더 열심히 해야겠다는 생각이 든다.