반응형
electron-react
설치하기
git clone --depth 1 --single-branch --branch master https://github.com/electron-react-boilerplate/electron-react-boilerplate.git my-electreact cd my-electreact yarn |
하면 패키지들이 다운로드 된다.
다운로드가 다되면 걸린시간이 출력되는데 3분정도걸렸다.
Done in 172.61s.
개발 시작하기.
yarn dev로 개발환경으로 앱을 시작시키면
hot-module-replacement 모드로 렌더러 프로세스를 실행켜주고
렌더러 프로세스로 hot update를 보내줄 webpack dev server도 실행시켜준다.
yarn dev |
Todo 리스트 만들기..
-. 개별 CSS 파일 적용법 : CSS Module을 사용함.
import styles from './TodoListTemplate.css
이렇게 선언하고
<div className={styles.title}>오늘 할 일</div>
이렇게 호출해서 써야한다.
=> classnames 모듈 사용...
yarn add classnames |
-. 타입 스크립트에 사용되는 코드들이 있다. 어떻게 처리해야할지 모르겠다.
-. //@flow라는 주석이 있다. 지워도 되는 듯하다.
소스들..
Home.js
// @flow
import React, { Component } from 'react';
import TodoListTemplate from './TodoListTemplate';
import Form from './Form';
import TodoItemList from './TodoItemList';
export default class Home extends Component {
id = 3; // 이미 0,1,2 가 존재하므로 3으로 설정
state = {
input: '',
todos: [
{ id: 0, text: ' 리액트 소개', checked: false },
{ id: 1, text: ' 리액트 소개', checked: true },
{ id: 2, text: ' 리액트 소개', checked: false }
]
};
handleChange = e => {
this.setState({
input: e.target.value
});
};
handleCreate = () => {
const { input, todos } = this.state;
this.setState({
input: '',
todos: todos.concat({ id: this.id++, text: input, checked: false })
});
};
handleKeyPress = e => {
if (e.key === 'Enter') {
this.handleCreate();
}
};
handleRemove = id => {
const { todos } = this.state;
this.setState({ todos: todos.filter(todo => todo.id != id) });
};
handleToggle = id => {
const { todos } = this.state;
const index = todos.findIndex(todo => todo.id === id);
const selected = todos[index];
const nextTodos = [...todos];
nextTodos[index] = {
...selected,
checked: !selected.checked
};
this.setState({ todos: nextTodos });
};
render() {
const { input, todos } = this.state;
const {
handleChange,
handleCreate,
handleKeyPress,
handleRemove,
handleToggle
} = this;
return (
<TodoListTemplate
form={
<Form
value={input}
onKeyPress={handleKeyPress}
onChange={handleChange}
onCreate={handleCreate}
/>
}
>
<TodoItemList
todos={todos}
onToggle={handleToggle}
onRemove={handleRemove}
/>
</TodoListTemplate>
);
}
}
Home.css
.container {
position: absolute;
top: 30%;
left: 10px;
text-align: center;
}
.container h2 {
font-size: 5rem;
}
.container a {
font-size: 1.4rem;
}
Form.js
import React from 'react';
import styles from './Form.css';
const Form = ({ value, onChange, onCreate, onKeyPress }) => {
return (
<div className={styles.form}>
<input value={value} onChange={onChange} onKeyPress={onKeyPress} />
<div className={styles.create_button} onClick={onCreate}>
추가
</div>
</div>
);
};
export default Form;
Form.css
.form {
display: flex;
}
.form input {
flex: 1;
font-size: 1.25 rem;
outline: none;
border: none;
border-bottom: 1px solid #c5f6fa;
}
.create_button {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
padding-left: 1rem;
padding-right: 1rem;
margin-left: 1rem;
background: #22b8cf;
border-radius: 3px;
color: white;
font-weight: 600;
cursor: pointer;
}
.create_button:hover {
background: #3bc9db;
}
TodoItem.js
import React, { Component } from 'react';
import classNames from 'classnames';
import styles from './TodoItem.css';
export default class TodoItem extends Component {
render() {
const { text, checked, id, onToggle, onRemove } = this.props;
console.log('checked : ' + checked);
let todoText = [];
if (checked) {
todoText = (
<React.Fragment>
<div className={classNames(styles.todo_text, styleMedia.checked)}>
<div>{text}</div>
</div>
<div className={styles.check_mark}>✓</div>
</React.Fragment>
);
} else {
todoText = (
<React.Fragment>
<div className={[styles.todo_text]}>
<div>{text}</div>
</div>
</React.Fragment>
);
}
return (
<div className={styles.todo_item} onClick={() => onToggle(id)}>
<div
className={styles.revmove}
onClick={e => {
e.stopPropagation();
onRemove(id);
}}
>
×
</div>
{todoText}
</div>
);
}
}
TodoItem.css
.todo_item {
padding: 1rem;
display: flex;
align-items: center;
cursor: pointer;
transition: all 0.15s;
user-select: none;
}
.todo_item:hover {
background: #e3fafc;
}
/* todo-item 에 마우스가 있을때만 .remove 보이기 */
.todo_item:hover .remove {
opacity: 1;
}
/* todo-item 사이에 윗 테두리 */
.todo_item + .todo_item {
border-top: 1px solid #f1f3f5;
}
.remove {
margin-right: 1rem;
color: #e64980;
font-weight: 600;
opacity: 0;
}
.todo_text {
flex: 1; /* 체크, 엑스를 제외한 공간 다 채우기 */
word-break: break-all;
}
.checked {
text-decoration: line-through;
color: #adb5bd;
}
.check_mark {
font-size: 1.5rem;
line-height: 1rem;
margin-left: 1rem;
color: #3bc9db;
font-weight: 800;
}
TodoItemList.js
import React, { Component } from 'react';
import TodoItem from './TodoItem';
class TodoItemList extends Component {
shouldComponentUpdate(nextProps, nextState) {
return this.props.todos !== nextProps.todos;
}
render() {
const { todos, onToggle, onRemove } = this.props;
const todoList = todos.map(({ id, text, checked }) => {
return (
<TodoItem
id={id}
text={text}
checked={checked}
onToggle={onToggle}
onRemove={onRemove}
key={id}
/>
);
});
return <div>{todoList}</div>;
}
}
export default TodoItemList;
TodoListTemplate.js
import React from 'react';
import styles from './TodoListTemplate.css';
const TodoListTemplate = ({ form, children }) => {
//children : 태그사이 내용.
return (
<main className={styles.todo_list_template}>
<div className={styles.my_title}>오늘 할 일</div>
<section className={styles.form_wrapper}>{form}</section>
<section className={styles.todos_wrapper}>{children}</section>
</main>
);
};
export default TodoListTemplate;
TodoListTemplate.css
.todo_list_template {
background: white;
width: 512px;
box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23); /* 그림자 */
margin: 0 auto; /* 페이지 중앙 정렬 */
margin-top: 4rem;
}
.my_title {
padding: 2rem;
font-size: 2.5rem;
text-align: center;
font-weight: 100;
background: #22b8cf;
color: white;
}
.form_wrapper {
padding: 1rem;
border-bottom: 1px solid #22b8cf;
}
.todos_wrapper {
min-height: 5rem;
}