By Sheldon L | Published at 2020-03-13 | Updated at 2020-03-13 |
React Developer Tools in chrome extension
Install with sudo npm -g i create-react-app
or just start with npx create-react-app my_app
npx create-react-app my-app
cd my-app
code .
npm start
npm i uuid
npm i react-router-dom
npm i axios # http req
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import axios from 'axios';
import Header from './components/layout/Header';
import About from './components/pages/About';
import Todos from './components/Todos';
import AddTodo from './components/AddTodo';
import './App.css';
const uuid=require('uuid');
class App extends Component {
state = {
todos: []
};
componentDidMount() {
axios.get('https://jsonplaceholder.typicode.com/todos?_limit=10')
.then(res => this.setState({ todos: res.data }))
.catch(err => console.log(err))
}
// Toggol markComplete
markComplete = (id) => {
this.setState({ todos: this.state.todos.map(todo => {
if (todo.id === id) {
todo.completed = !todo.completed
}
return todo;
}) })
}
// Toggle delTodo
delTodo = (id) => {
axios.delete(`https://jsonplaceholder.typicode.com/todos/${id}`)
.then(this.setState({todos: [...this.state.todos.filter(todo => todo.id !== id)] }))
}
// Toggl addTodo
addTodo = (title) => {
axios.post('https://jsonplaceholder.typicode.com/todos',
{
id: uuid.v4(),
title: title,
completed: false,
}
).then(res => this.setState({ todos: [...this.state.todos, res.data] }))
.catch(err => console.log(err))
}
render() {
return (
<Router>
<div className="App">
<div className="container">
<Header />
<Route exact path="/" render={props => (
<React.Fragment>
<AddTodo
addTodo={this.addTodo}
/>
<Todos todos={this.state.todos}
markComplete={this.markComplete}
delTodo={this.delTodo}
/>
</React.Fragment>
)}
/>
<Route exact path="/about" component={About} />
</div>
</div>
</Router>
);
};
}
export default App;
App.css
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, Helvetica, sans-serif;
line-height: 1.4;
}
a {
color: #333;
text-decoration: none;
}
.container {
padding: 0 0;
}
.btn {
display: inline-block;
border: none;
background: #555;
color: #fff;
padding: 7px 20px;
cursor: pointer;
}
.btn:hover {
background: #666;
}
components/layout/Header.js
import React from 'react'
import { Link } from 'react-router-dom';
function Header() {
return ( // in function return = return + render
<div>
<header style={headerStyle}>
<h1>TodoList</h1>
<Link style= to="/">Home</Link>{' | '}
<Link style= to="/about">About</Link>
</header>
</div>
)
}
const headerStyle = {
background: '#333',
color: '#fff',
textAlign: 'center',
padding: '10px',
}
export default Header;
components/pages/About.js
import React from 'react'
function About() {
return (
<React.Fragment>
<h1>About</h1>
<p>This is the TodoList v1.0.0</p>
</React.Fragment>
)
}
export default About
components/Todos.js
import React, { Component } from "react";
import TodoItem from "./TodoItem";
import PropTypes from 'prop-types';
class Todos extends Component {
render() {
return this.props.todos.map((todo) => (
<TodoItem
key={todo.id}
todo={todo}
markComplete={this.props.markComplete}
delTodo={this.props.delTodo}
/>
))
}
}
// PropTypes
Todos.propTypes = {
todos: PropTypes.array.isRequired,
markComplete: PropTypes.func.isRequired,
delTodo:PropTypes.func.isRequired,
}
export default Todos;
components/TodoItem.js
import React, { Component } from 'react';
import PropTypes from 'prop-types';
export class TodoItem extends Component {
getCompleteStyle = () => {
return {
background: '#f4f4f4',
padding: '10px',
borderBottom: '1px #ccc dotted',
textDecoration: this.props.todo.completed ? 'line-through' : 'none'
}
}
render() {
const { id, title } = this.props.todo
return (
<div style={this.getCompleteStyle()}>
<p>
<input type="checkbox"
onChange={this.props.markComplete.bind(this, id)}
defaultChecked={this.props.todo.completed ? true : false}
/>
{' '} { title }
<button onClick={this.props.delTodo.bind(this, id)} style={btnStyle}>x</button>
</p>
</div>
)
}
}
// PropTypes
TodoItem.propTypes = {
todo: PropTypes.object.isRequired,
markComplete: PropTypes.func.isRequired,
delTodo:PropTypes.func.isRequired,
}
const btnStyle = {
background: '#ff0000',
color: '#fff',
border: 'none',
padding: '1px 5px',
borderRadius: '50%',
cursor: 'pointer',
float: 'right'
}
export default TodoItem
components/AddTodo.js
import React, { Component } from 'react'
import PropTypes from 'prop-types'
export class AddTodo extends Component {
state = {
title: ''
}
onSubmit = (e) => {
e.preventDefault();
this.props.addTodo(this.state.title);
this.setState({ title: '' })
}
onChange = (e) => this.setState({
[e.target.name]: e.target.value // name="title" in <input>
});
render() {
return (
<form onSubmit={this.onSubmit} style=>
<input
style=
type="text"
name="title"
placeholder="Add todo..."
value={this.state.title}
onChange={this.onChange}
/>
<input
style=
type="submit"
value="Submit"
className="btn"
/>
</form>
)
}
}
// PropTypes
AddTodo.propTypes = {
addTodo: PropTypes.func.isRequired,
}
export default AddTodo