https://www.youtube.com/watch?v=A4Grb-bm0Ok&list=PL7jH19IHhOLMTVBzUkbN74h1nyXW7VhYV
[Stack]
- GraphQL
- Apollo
- ReactJS
- StyledComponent
https://github.com/daheeahn/nomad-notes
GraphQL, Apollo로 local state 관리, 오프라인으로 !!
No 리덕스 No Context Api !!!!!
니꼴피셜: 리덕스 버림. Apollo, GQL과 함께면, 리덕스 필요 없음
GQL이 Redux의 API 부분만 대체하는줄 아는데,
GQL로 local state 다루는걸 보여줄거야. !!!! 와웅
다 local state야. no api~
use local storage
리덕스 -> GQL, Apollo 조합으로 바꾸길 바라!
나에게 너무나도 적합한 강의임
1. create react app
npx로 진행되는 앱을 만들어줄거야
npx는 create-react-app 없이 앱을 만들 수 있어.
그래서 create-react-app 다운 받을 필요 없음
단지 npx를 통해 앱을 실행 시키면 됨.
npx create-react-app nomad-notes
2. 깃헙 repo 만들기
https://github.com/daheeahn/nomad-notes
1에서 만든 폴더랑 연결시켜주기
3. 필요없는거 다 지우기
App.css
App.test.js
index.css
logo.svg
serviceWorker.js
setupTests.js
이 파일 관련 코드도 다 지우기!
4.
Apllo boost: 앱에 대한 것들을 도와주는 gql 클라이언트인데, 이게 지금은 필요 없음.
Apollo boost에서 온 client는 http쪽으로 손볼게 넘 많아.
Api를 비롯한 다른 configuration도 그렇고,
여기서 우리가 해야하는건 client를 만들건데, cache에서만 일하고 오프라인으로만 있을 클라이언트를 만들거야.
그래서 apllo-boost를 사용하지 않아.
yarn add apollo-cache-inmemory apollo-client graphql react-apollo styled-components styled-reset react-textarea-autosize graphql-tag apollo-link-state react-dom
graphql-tag: 그래야 query를 넣을 수 있어.
package.json에서 잘 추가됐는지 확인해보기!
5.
styled-component 파일 만드는건 css 셋업은 생략할게
Styled-components는 typed component라고 한다.
6. client 생성. apollo를 오프라인으로 생성.
client: 오프라인, 캐싱 등등을 담당하게 하는거야
src/Components 폴더 생성
src/Routes 폴더 생성
src/Apollo.js 생성해서 Apollo 오프라인 셋업 할거고
필요한거 전부 import.
그리고 이 client를 react Apollo provider에 export 할거야
import { defaults, resolvers, typeDefs } from "./clientState";
import { ApolloClient } from "apollo-client";
import { ApolloLink } from "apollo-link";
import { InMemoryCache } from "apollo-cache-inmemory";
import { withClientState } from "apollo-link-state";
// apollo-boost 쓰면 이걸 자동으로 해줌.
// 자동으로 될 부분까지 전부 수동으로 해볼거야
// internet api 온라인 부분은 빼고말이야
const cache = new InMemoryCache();
const stateLink = withClientState({
// default state가 필요해. notes는 타입 정의나 resolvers같은걸 필요로 해. 이부분에 앱에 필요한 모든 로직을 넣어야해
// 그러니까 모든 로직을 웹에있는 clientState에 적어줘야 하는거야.
// reseolver 같은 경우는 오프라인으로 해주고, 타입선언, default state도. 여기서 해줘야 해.
// 왜냐면 여기는 client state니까
// clientState는 cache가 필요해. 내가 clientState를 어디에 저장할건지 지정을 해줘야 해
// 타입 정의도 필요해
// 디폴트, 리졸버가 필요햐ㅐ. 이걸 전부 import
cache,
typeDefs,
defaults,
resolvers
}); // 아폴로에서 거의 모든 명령어들은 전부 링크가 돼. http link도 있고 error link, state link도 있어
// 여기선 http link & error link 만들거야. subscription을 위한 web socket을 넣거나.... 아니면 전부를 넣거나!
const client = new ApolloClient({
cache,
link: ApolloLink.from([stateLink])
});
export default client;
src/clientState.js
export const defaults = {};
export const resolvers = {};
export const typeDefs = {};
src/index.js
import { ApolloProvider } from "react-apollo"; // add this code
import App from "./App";
import React from "react";
import ReactDOM from "react-dom";
import client from "./Apollo"; // add this code
ReactDOM.render(
<ApolloProvider client={client}> // add this code
<App />
</ApolloProvider>, // add this code
document.getElementById("root")
);
7. yarn start
콘솔에서 에러 안나는지도 확인해주기!
이걸 apollo-boost로 하려고 했는데 http 링크가 필요해서 제대로 작동하지 않았어. 그래서 그냥 수동으로 했어
8. typeDef, resolvers, default
logic 다 훑어보고, apollo client dev tools로 보는법
모든 queries 여기서 실행되는 것도 보고 테스트할거야.
그리고 html css 넣는것까지 볼거임
9. typedef
schema를 documentation explorer 에서 사용할거야 (개발자도구-Apollo? 이게 gql 익스텐션일거임)
저 gql 익스텐션은 새로고침하면 바보가 됨. so, reload frame을 눌러줘야해 우클릭해서
src/clientState.js
export const defaults = {
// 디폴트로 할 수 있는 쿼리
notes: [
{
__typename: "Note", // apollo로 localState랑 일할 때는 이걸 꼭 써줘야해. 규칙.
id: 1,
title: "First",
content: "Second"
}
]
};
export const typeDefs = [
// 우리의 schema가 어떤 형태인지 보여주는거야 by graphql 언어. 서버가 없기 때문에 이렇게 한댜
`
schema {
query: Query
mutation: Mutation
}
type Query {
notes: [Note]!
note(id: Int!): Note
}
type Mutation {
createNote(title: String!, content: String!): Note
editNote(id: Int!, title: String, content: String): Note
}
type Note {
id: Int!
title: String!
content: String!
}
`
]; // createNote랑 editNote는 return 없어. 따로 필요 없으니까!
export const resolvers = {
Mutation: {},
Query: {}
};
그리고 yarn start, Apollo 탭으로 가서 reload frame, load from cache 체크, 재생 버튼 눌러보면... @client 없이도 됨!
그리고 쿼리 입력!
like this~
?? @client 없으면 원래 어떤식으로 가는냐??????????????????????????????????????????????????????????????
왜 cache에서 처리하지 ㅇ낳지?????????????????
이 쿼리는 디폴트로 원래(?) 할 수 있다는데? 근데 내가 src/clientState.js 에
defaults로 notes라적어놔서 할 수 있었던게 아니라?? 모르겠다.
10. 버그 수정 (1.3.1) 다시봐야할듯 / queryStore 에러
Apollo 익스텐션에서 캐시를 제대로 보고 싶었는데, 이렇게 하면 버그 사라짐,,, 흠
App.js
import { GET_NOTES } from "./queries"; // add this line
import { Query } from "react-apollo"; // add this line
import React from "react";
function App() {
return (
<div className="App">
<Query query={GET_NOTES}>{() => null}</Query> // add this line
<p>hi</p>
</div>
);
}
export default App;
src/queries.js
?
근데 그럼에도 불구하고 나는 아예 익스텐션 안먹힘
11. Note Query
바로
쿼리 하나를 입력할 수 있음. notes
{
notes @client {
id
title
}
}
react apollo는 dev tool이 하나 있는데, 디폴트 설정으로 오프라인 작업을 할 수없어.
시스템 상에서 API(: ???????)로 넘어가려고 할거야 그래서 load from cache를 할 수 없어
?? 그럼 react apollo tool의 문제?
그래서 @client를 하거나 // 이걸 하세요
재생 버튼 눌러도 될거야 (프레임 새로고침. 안되면 캐시 탭에서 프레임 새로고침.)
Reload Frame 계속 해주고~
12. 근데 Apollo 익스텐션에서 다시 우클릭 - 검사(Inspect) 누르면 또 뭐가 나오는데, 거기에 콘솔에 버그가 있음. 일단 쿼리는 되니까 쿼리부터 하자. 그리고 캐시도 되는데? 10번을 안해도 되는데
13. Query, Fragment
src/clientState.js
export const resolvers = {
Mutation: {},
Query: {
// 보통의 gql resolver와 같다.
note: (_, variables, context) => {
// context엔 아무거나 넣어도 돼.
console.log(variables);
return null; // 언제나 resolver에서 무언가를 리턴 해야해!!!!!!!!!! 규칙이야 ******
}
}
};
그리고 익스텐션에서
note(id: 1)@client {
id
title
}
}
하면~~~ 콘솔에 variables가 찍힘!
@client가 있으면 어떤식이든 콘솔에 찍히긴 한다는거.
cache에서 id: 1 노트를 가져오는거야.
default에 note array 있으니까!
-----또 하나의 에러-----
Apollo Client Developer Tools에서 스키마를 인식하지 못하고 우측의 Documentation Explorer에 No Schema Available이라는 메시지가 뜬다면 확인해보세요. 제 경우에는 시스템 내 schema와 type Query가 이미 존재했기 때문에 typeDefs 안에 재선언 한 것이 문제가 되어 에러를 뿜었습니다. 첨부한 이미지처럼 schema와 type Query 앞에 extend를 붙여 확장함으로써 중복 선언을 피해주니 정상출력되는 것을 확인할 수 있었습니다.
src/clientState.js
export const resolvers = {
Mutation: {},
Query: {
// 보통의 gql resolver와 같다.
note: (_, variables, { cache }) => {
// context엔 아무거나 넣어도 돼.
const id = cache.config.dataIdFromObject({
__typename: "Note",
id: variables.id
}); // cache에서 정보 가져오기
console.log(id);
return null; // 언제나 resolver에서 무언가를 리턴 해야해!!!!!!!!!! 규칙이야 ******
}
}
};
이렇게 하고 note 쿼리 한 번 실행하면, Note:1 이 찍힌다 콘솔에!
이제 이 id를 가지고 있는 fragment(object같은거)를 찾을거야 gql apollo cache에서 찾을 수 있느 ㄴobj같은거
react apollo cache가 작동하는 방식이 notes array로 가서 찾는게 아니라 cache에서 fragment만 가져올수있는 방법이 따로 있어.
우리가 id가 있는 한! array가 따로 있는한!!! 상관없이 찾을 수 있다구.
src/fragment.js
import gql from "graphql-tag";
// 내가 재사용하고 싶은거야! 반복해서 입력하고 싶지 않을때. 수정.추가할 때나 하나만 찾고싶을때나... 암튼 그럴 때 fragment를 이용해 재사용 하는거야
export const NOTE_FRAGMENT = gql`
fragment NoteParts on Note {
id
title
content
}
`;
// id title content는 clientState에서 type Note 에서 가져오는거야!
src/clientState.js
export const resolvers = {
Mutation: {},
Query: {
// 보통의 gql resolver와 같다.
note: (_, variables, { cache }) => {
// context엔 아무거나 넣어도 돼.
const id = cache.config.dataIdFromObject({ // 이게 devTools에서 작동하고, 다른거 getCacheKey? 이런건 안된대.. 왜지
__typename: "Note",
id: variables.id
}); // cache에서 정보 가져오기
console.log(id);
// id만 있으면 cache에 있는 fragment를 가져올 수 있어
const note = cache.readFragment({ fragment: NOTE_FRAGMENT, id });
return note;
// return null; // 언제나 resolver에서 무언가를 리턴 해야해!!!!!!!!!! 규칙이야 ******
}
}
};
const note부분 추가
reload frame하고 id가 1인 노트를 찾아보자!
14. add note Mutation
src/clientState.js - resolvers에
// Query랑 동등한 위치에 추가
Mutation: {
createNote: (_, variables, { cache }) => {
// 먼저 cache에 있는 note arr를 가져온다.
const noteQuery = cache.readQuery({ query: GET_NOTES });
console.log(noteQuery);
}
}
src/queries.js 생성
// clinetState에 이 쿼리들 써야 함
import gql from "graphql-tag";
export const GET_NOTES = gql`
{
notes @client {
id
title
content
}
}
`;
그리고 apollo 개발자도구 가서
mutation {
createNote(title:"Hello", content: "what's up") @client {
id
}
}
돌려보면 콘솔이 찍힌다! @client 빼먹으면 콘솔 안찍힘
이제 제대로 해보자
Mutation: {
createNote: (_, variables, { cache }) => {
// 먼저 cache에 있는 note arr를 가져온다.
// const noteQuery = cache.readQuery({ query: GET_NOTES });
const { notes } = cache.readQuery({ query: GET_NOTES }); // noteQuery안에 notes가 있으니까
const { title, content } = variables;
// 새로운 노트는 타입이 있어야 해. typename도.
const newNote = {
__typename: "Note", // apollo가 구성에 문제 없는지 자동으로 점검해줘 type에 없는 Diary 이런거 추가하면 안된다고 알려줘. 안전하지!
title,
content,
id: notes.length + 1
};
cache.writeData({
data: {
notes: [newNote, ...notes] // ...notes 꼭 해줘야 해! 안그럼 날아가.
}
});
console.log(notes);
return newNote;
}
}
reload frame
load from cache 체크
mutation {
createNote(title:"Hello", content: "what's up") @client {
id
}
}
그리고
이렇게 쿼리 날리면 추가된 notes를 볼 수 있다!
근데 load from cache 체크하고 @client 없애고 note query 날려도 됨 (안될 때도 있는데 왜그런지는 몰라)
암튼! 그렇다!
이거를 command + r 하면 (새로고침) 다 없어지고 초기값인 id 1인 노트만 남겠지! note query 날리면.
근데 @client 없이 load from cache 체크해야 함!
15. edit note
// in Mutation
editNote: (_, { id, title, content }, { cache }) => {
const noteId = cache.config.dataIdFromObject({
// 왜 하는거지? -> noteId: "Note:1" 이걸 ReadFragment할 때 넣어야 된다.
__typename: "Note",
id
}); // cache에서 정보 가져오기
const note = cache.readFragment({ fragment: NOTE_FRAGMENT, id: noteId });
// writeData 대신 fragment 만들어줄거야. 한개의 fragment를 update할거거든
const updatedNote = {
...note,
title,
content
};
cache.writeFragment({
id: noteId,
fragment: NOTE_FRAGMENT, // fragment 어떤 모양의 데이터 업데이트 할건지
data: updatedNote
});
console.log(updatedNote);
return updatedNote;
}
이렇게 해도됨.
editNote: (_, { id, title, content }, { cache }) => {
// const noteId = cache.config.dataIdFromObject({
// __typename: "Note",
// id
// });
// const note = cache.readFragment({
// fragment: NOTE_FRAGMENT,
// id: noteId
// });
// const updatedNote = {
// ...note,
// title,
// content
// };
// cache.writeFragment({
// id: noteId,
// fragment: NOTE_FRAGMENT,
// data: updatedNote
// });
// return updatedNote;
const { notes } = cache.readQuery({ query: GET_NOTES });
console.log(notes);
const target = notes.find(n => n.id === id);
target.title = title;
target.content = content;
cache.writeData({
data: {
notes: notes
}
});
return target;
}
+ 성능이 안좋긴 한데.... .이게 더 좋네ㅋ? 가독성이 좋네?ㅋ
mutation {
editNote(id: 1, title: "new title", content: "new content") @client {
id
}
}
근데 title이나 content 없으면 원래 것이 들어간다. 근데 콘솔에 경고뜸
그냥 둘다 넣어줘야 하는걸로!
16. Router and Routes
16-1. 폴더 정리
src/Routes 폴더에
Add, Edit, Note, Notes 폴더 만든다
src/Components/App에
App.js 옮겨준다.
index.js 파일도 하나 만든다.
import App from "./App";
export default App;
16-2. apollo랑 query 써줄거야
4개의 라우터 만들어줄거야
우리가 전부를 볼 수 있는 라우트
나의 노트 볼 때
수정할때
노트추가할때 (form 비어있음)
crud.
Notes부터 만들어주자
src/Components/App/App.js
import { BrowserRouter, Route, Switch } from "react-router-dom";
import Notes from "../../Routes/Notes";
import Note from "../../Routes/Note";
import Add from "../../Routes/Add";
import Edit from "../../Routes/Edit";
import React from "react";
function App() {
return (
<BrowserRouter>
<Switch>
<Route exact={true} path={"/"} component={Notes} />
<Route path={"/note/:id"} component={Note} />
<Route path={"/add"} component={Add} />
<Route path={"/edit/:id"} component={Edit} />
</Switch>
</BrowserRouter>
);
}
export default App;
exact는 Notes에만 있네
1) src/Routes/Notes/Notes.js
import React from "react";
export default class Notes extends React.Component {
render() {
return "hi";
}
}
2) src/Routes/Notes/index.js
import Notes from "./Notes";
export default Notes;
1) 2) 를 Note, Add, Edit 폴더에도 똑같이 만들어준다. 이름만 변경하고!
17. Notes Route
Query를 만들려면
src/Routes/Notes/Notes.js
import { GET_NOTES } from "../../queries"; // shared query 이거 사용!!
import { Link } from "react-router-dom";
import Plus from "../../Assets/plus.png";
import { Query } from "react-apollo";
import React from "react";
const Notes = () => {
console.log(Plus);
return (
<>
<div style={{ display: "flex" }}>
<h1>Dahee Note</h1>
<Link to={"/add"}>
<img src={Plus} width={50} height={50} />
</Link>
</div>
<Query query={GET_NOTES}>
{({ data }) => {
console.log(data);
return (
data?.notes?.map(note => (
<Link to={`/edit/${note.id}`} key={note.id}>
<h5>{note.title}</h5>
</Link>
)) || null
);
}}
</Query>
</>
);
};
export default Notes;
{ data } 주목! data.data라 destruct한거임
18. 노트를 클릭했을 때 변경되는 부분! note view
@client는 오프라인일 때 꼭 넣어줘야해 쿼리에
GET_NOTE는 많이 필요해 한개의노트 불러올 때, 수정을 할 때도 . 그래서 queries.js에 ~~
src/queries.js
import { NOTE_FRAGMENT } from "./fragment";
// clinetState에 이 쿼리들 써야 함
import gql from "graphql-tag";
// export const GET_NOTES = gql` // remove this code
// {
// notes @client {
// id
// title
// content
// }
// }
// `;
export const GET_NOTES = gql`
{
notes @client {
...NoteParts // add this code
}
}
${NOTE_FRAGMENT} // add this code
`;
// add this code
export const GET_NOTE = gql`
query getNote($id: Int!) {
note(id: $id) @client {
...NoteParts
}
}
${NOTE_FRAGMENT}
`;
이 GET_NOTE를 이제 이용하면 되겠다!
- 마크다운 렌더링
yarn add react-markdown-renderer
src/Routes/Note/Note.js
import { GET_NOTE } from "../../queries";
import { Link } from "react-router-dom";
import MarkdownRenderer from "react-markdown-renderer";
import { Query } from "react-apollo";
import React from "react";
const Note = props => {
const {
match: {
params: { id }
}
} = props;
return (
<Query query={GET_NOTE} variables={{ id }}>
{({ data }) => {
console.log("data", data);
return (
<>
<h1>{data?.note?.title}</h1>
<Link to={`/edit/${id}`}>
<h4>Edit</h4>
</Link>
<MarkdownRenderer markdown={data?.note?.content} />
</>
);
}}
</Query>
);
};
export default Note;
19. Form
edit 할 수 있는 form !
add에도 사용됨.
src/Components/Editor/index.js
src/Components/Editor/Editor.js
폴더랑 파일 만들기!
src/Components/Editor/index.js
import Editor from "./Editor";
export default Editor;
src/Components/Editor/Editor.js
import React, { useState } from "react";
import MarkdownRenderer from "react-markdown-renderer";
const Editor = ({ id: i, title: t, content: c, onSave }) => {
const [id, setId] = useState(i || null);
const [title, setTitle] = useState(t || "");
const [content, setContent] = useState(c || "");
return (
<div>
<input
placeholder={"Untitled..."}
style={{ borderColor: "transparent", fontSize: 40 }}
value={title}
onChange={e => setTitle(e.target.value)}
/>
<br />
<textarea
rows={5}
placeholder={"Content..."}
style={{ borderColor: "transparent", fontSize: 20 }}
value={content}
onChange={e => setContent(e.target.value)}
/>
<br />
<MarkdownRenderer markdown={content} />
<br />
<button onClick={() => onSave(title, content, id)}>Save</button>
</div>
);
};
export default Editor;
대충 이렇게 세팅~
1) add
2) edit
render 할 때 중요한건, mount 전에 state 만들어주는거야.
onSave function은 add라우트를 통해 받을거야, edit은 또 다르겠지!
로컬변수는 useRef를 사용한다!
import React, { useRef } from 'react';
const RefSample = () => {
const id = useRef(1);
const setId = (n) => { id.current = n; }
const printId = () => { console.log(id.current); }
return ( <div> refsample </div> );
};
.current로 바꾸고 조회하고 하면 된다!
19-1. Add
src/Routes/Add/Add.js
import React, { useRef } from "react";
import Editor from "../../Components/Editor";
import { Mutation } from "react-apollo";
import gql from "graphql-tag";
const CREATE_NOTE = gql`
mutation createNote($title: String!, $content: String!) @client {
createNote(title: $title, content: $content) {
id
}
}
`;
const Add = ({ history: { push } }) => {
// destruct 잘한다!!
const createNoteRef = useRef(null);
const _onSave = (title, content) => {
if (title !== "" && content !== "") {
createNoteRef.current({ variables: { title, content } });
push("/"); // redirect
}
};
return (
<>
<Mutation mutation={CREATE_NOTE}>
{createNote => {
createNoteRef.current = createNote;
return <Editor onSave={_onSave} />;
}}
</Mutation>
</>
);
};
export default Add;
- push: 리다이렉트 하는거임 (props 안에 history가 있음)
- <Mutation>
19-2. Edit
import { Mutation, Query } from "react-apollo";
import React, { useRef } from "react";
import Editor from "../../Components/Editor";
import { GET_NOTE } from "../../queries";
import gql from "graphql-tag";
export const EDIT_NOTE = gql`
mutation editNote($id: Int!, $title: String!, $content: String!) @client {
editNote(id: $id, title: $title, content: $content)
}
`;
const Edit = props => {
const {
match: {
params: { id }
}
} = props;
const _onSave = (title, content, id) => {
const {
history: { push }
} = props;
if (title !== "" && content !== "" && id) {
editNoteRef.current({ variables: { title, content, id } });
// push(`/note/${id}`)
push("");
}
};
const editNoteRef = useRef(null);
return (
<>
<Query query={GET_NOTE} variables={{ id }}>
{({ data }) =>
data?.note ? (
<Mutation mutation={EDIT_NOTE}>
{editNote => {
editNoteRef.current = editNote;
return (
<Editor
onSave={_onSave}
title={data.note.title}
content={data.note.content}
id={data.note.id}
/>
);
}}
</Mutation>
) : null
}
</Query>
</>
);
};
export default Edit;
<Mutation>
{editNote
이게 내가 정의한 editNote함수가 오는건가?
20. 오프라인 Saving the Notes Offline
Note를 만들었을 때나 수정할 때 function이 작동하게 할거임. query를 읽는거야.
cache에서 모든 노트 불러오고, local storage에 저장하는거임.
src/offline.js 생성
import { GET_NOTES } from "./queries";
export const saveNotes = cache => {
// query를 읽게 함
// note를 저장하면 cache를 주고 노트가 저장되면 모든 노트의 arr를 받는거지. (이건 clientState에서 하는거같은데) local storage에도 저장하고!
const { notes } = cache.readQuery({ query: GET_NOTES }); // noteQuery안에 notes가 있으니까
const jsonNotes = JSON.stringify(notes);
try {
localStorage.setItem("notes", jsonNotes);
} catch (error) {
console.log(error);
}
};
// title을 바꿨으면 나는 모든 앱의 리스트 불러오고, 업데이트 된 리스트를 로컬 스토리지에 옮겨주는거지.
src/clientState.js
Mutation - createNote, editNote return 직전에 saveNotes(cache) 넣어주기!
saveNotes(cache); // cache is from resolvers
개발자도구 - Application - Storage
이렇게 로컬스토리지 볼 수 있음!
key값 변경도 가능 이게 바뀌면 restore 못하겠지
21. Restore
src/clientState.js
import { saveNotes, restoreNotes } from "./offline";
export const defaults = {
// 디폴트로 할 수 있는 쿼리
notes: restoreNotes()
};
이제 디폴트로 로컬스토리지에 있는 노트를 가져온다!
src/offline.js
export const restoreNotes = () => {
const notes = localStorage.getItem("notes");
if (notes) {
try {
const parsedNotes = JSON.parse(notes);
return parsedNotes;
} catch (error) {
console.log(error);
return [];
}
}
return [];
};
개발자도구 - Apollo - cache & reload frame
cache에도 있을 것!
local state를 위한 dev tool이 아직 없다면...
api 작업을 해야한다면 graphql이 최선일거야
현재 tool이 별로 없는지라.
무슨말이지 이게?
redux랑 비교했을 때 loggers, middlewares 같은 것들이 많으니까
시간이 얼마나 걸리냐의 차이겠지.
[코드 챌린지]
날짜 sort
creation date로 sort하기
지워도 보기
** 추가사항
TextareaAutoSize
const input = styled(TextareaAutoSize)`~`
유저가 스크롤 안해도 높이에 맞춰 텍스트박스 맞춰주는거.
** ????????
apollo-boost client
local state
더 단순한 방법이.... 분명히 있을거야@!!!!!!!!!!!!!!!!!!!!!!!!!!!
'Development > GraphQL' 카테고리의 다른 글
GQL서버 init (0) | 2020.04.10 |
---|---|
[GraphQL] passport로 인증기능 만들기 (2) | 2020.03.23 |
[GraphQL] apollo-server와 express 연결하기 (0) | 2020.03.22 |
[GraphQL / Apollo] 도입해보기 (0) | 2020.03.02 |