Last active
December 8, 2018 17:20
-
-
Save Dmitriy-8-Kireev/fd2db090d4fc34a949a1a84138f27d5c to your computer and use it in GitHub Desktop.
Набор универсальных фун-ий в app.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from "react"; | |
import axios from "axios"; | |
const DEFAULT_QUERY = "redux"; | |
const DEFAULT_HPP = "100"; | |
const PATH_BASE = "https://hn.algolia.com/api/v1"; | |
const PATH_SEARCH = "/search"; | |
const PARAM_SEARCH = "query="; | |
const PARAM_PAGE = "page="; | |
const PARAM_HPP = "hitsPerPage="; | |
class App extends Component { | |
_isMounted = false; | |
constructor(props) { | |
super(props); | |
this.state = { | |
results: null, | |
searchKey: "", | |
searchTerm: DEFAULT_QUERY, | |
error: null | |
}; | |
this.needsToSearchTopStories = this.needsToSearchTopStories.bind(this); | |
this.setSearchTopStories = this.setSearchTopStories.bind(this); | |
this.fetchSearchTopStories = this.fetchSearchTopStories.bind(this); | |
this.onSearchChange = this.onSearchChange.bind(this); | |
this.onSearchSubmit = this.onSearchSubmit.bind(this); | |
this.onDismiss = this.onDismiss.bind(this); | |
} | |
needsToSearchTopStories(searchTerm) { | |
return !this.state.results[searchTerm]; | |
} | |
setSearchTopStories(result) { | |
const { hits, page } = result; | |
const { searchKey, results } = this.state; | |
const oldHits = | |
results && results[searchKey] ? results[searchKey].hits : []; | |
const updatedHits = [...oldHits, ...hits]; | |
this.setState({ | |
results: { | |
...results, | |
[searchKey]: { hits: updatedHits, page } | |
} | |
}); | |
} | |
fetchSearchTopStories(searchTerm, page = 0) { | |
axios( | |
`${PATH_BASE}${PATH_SEARCH}?${PARAM_SEARCH}${searchTerm}&${PARAM_PAGE}${page}&${PARAM_HPP}${DEFAULT_HPP}` | |
) | |
.then(result => this.setSearchTopStories(result.data)) | |
.catch(error => this._isMounted && this.setState({ error })); | |
} | |
componentDidMount() { | |
this._isMounted = true; | |
const { searchTerm } = this.state; | |
this.setState({ searchKey: searchTerm }); | |
this.fetchSearchTopStories(searchTerm); | |
} | |
componentWillUnmount() { | |
this._isMounted = false; | |
} | |
onSearchChange(event) { | |
this.setState({ searchTerm: event.target.value }); | |
} | |
onSearchSubmit(event) { | |
const { searchTerm } = this.state; | |
this.setState({ searchKey: searchTerm }); | |
if (this.needsToSearchTopStories(searchTerm)) { | |
this.fetchSearchTopStories(searchTerm); | |
} | |
event.preventDefault(); | |
} | |
onDismiss(id) { | |
const { searchKey, results } = this.state; | |
const { hits, page } = results[searchKey]; | |
const isNotId = item => item.objectID !== id; | |
const updatedHits = hits.filter(isNotId); | |
this.setState({ | |
results: { | |
...results, | |
[searchKey]: { hits: updatedHits, page } | |
} | |
}); | |
} | |
render() { | |
const { searchTerm, results, searchKey, error } = this.state; | |
const page = | |
(results && results[searchKey] && results[searchKey].page) || 0; | |
const list = | |
(results && results[searchKey] && results[searchKey].hits) || []; | |
return ( | |
<div className="page"> | |
<div className="interactions"> | |
<Search | |
value={searchTerm} | |
onChange={this.onSearchChange} | |
onSubmit={this.onSearchSubmit} | |
> | |
Search | |
</Search> | |
</div> | |
{error ? ( | |
<div className="interactions"> | |
<p>Something went wrong.</p> | |
</div> | |
) : ( | |
<Table list={list} onDismiss={this.onDismiss} /> | |
)} | |
<div className="interactions"> | |
<Button | |
onClick={() => this.fetchSearchTopStories(searchKey, page + 1)} | |
> | |
More | |
</Button> | |
</div> | |
</div> | |
); | |
} | |
} | |
const Search = ({ value, onChange, onSubmit, children }) => ( | |
<form onSubmit={onSubmit}> | |
<input type="text" value={value} onChange={onChange} /> | |
<button type="submit">{children}</button> | |
</form> | |
); | |
const Table = ({ list, onDismiss }) => ( | |
<div className="table"> | |
{list.map(item => ( | |
<div key={item.objectID} className="table-row"> | |
<span style={{ width: "40%" }}> | |
<a href={item.url}>{item.title}</a> | |
</span> | |
<span style={{ width: "30%" }}>{item.author}</span> | |
<span style={{ width: "10%" }}>{item.num_comments}</span> | |
<span style={{ width: "10%" }}>{item.points}</span> | |
<span style={{ width: "10%" }}> | |
<Button | |
onClick={() => onDismiss(item.objectID)} | |
className="button-inline" | |
> | |
Dismiss | |
</Button> | |
</span> | |
</div> | |
))} | |
</div> | |
); | |
const Button = ({ onClick, className = "", children }) => ( | |
<button onClick={onClick} className={className} type="button"> | |
{children} | |
</button> | |
); | |
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Дополнительный вариант | |
import React, { Component, Fragment } from "react"; | |
class App extends Component { | |
render() { | |
return ( | |
<Fragment> | |
<div className="App"> | |
<Title /> | |
<Chat /> | |
</div> | |
</Fragment> | |
); | |
} | |
} | |
/* Fragment - оборачиваем вместо div */ | |
/* Title не имеет своего state, поэтому чтобы проще тестировать | |
компонент делаю не через class, а через функция */ | |
const Title = () => { | |
return <p className="title">My awesome chat</p>; | |
}; | |
class Chat extends Component { | |
state = { | |
messages: [], | |
messagesInput: "", | |
date: [] | |
}; | |
changeInputMessage = e => { | |
this.setState({ | |
messageInput: e.target.value | |
}); | |
}; | |
sendMessageOnEnter = e => { | |
let time = new Date(); | |
let index = Math.random(); | |
if (e.key === "Enter" && this.state.messageInput !== "") { | |
this.setState({ | |
messages: [ | |
...this.state.messages, | |
{ | |
text: this.state.messageInput, | |
date: time.toLocaleTimeString(), | |
key: index | |
} | |
] | |
}); | |
this.setState({ messageInput: "" }); | |
} | |
}; | |
render() { | |
return ( | |
<div className="chat"> | |
<div className="message-list"> | |
<div className="messages"> | |
{this.state.messages.map((message, index) => { | |
return ( | |
<Message key={index} text={message.text} date={message.date} /> | |
); | |
})} | |
</div> | |
</div> | |
<input | |
className="input-message" | |
value={this.state.messageInput} | |
onChange={this.changeInputMessage} | |
onKeyPress={this.sendMessageOnEnter} | |
/> | |
</div> | |
); | |
} | |
} | |
class Message extends Component { | |
render() { | |
const { text, date } = this.props; | |
return ( | |
<Fragment> | |
<span className="message">{text}</span> | |
<span className="time">{date}</span> | |
</Fragment> | |
); | |
} | |
} | |
export default App; | |
Реализация index.js | |
import React from "react"; | |
import ReactDOM from "react-dom"; | |
import App from "./app"; | |
// import "../src/index.css"; | |
import "./index.css"; более простой вариант |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from "react"; | |
class Pic extends Component { | |
state = { | |
isLoading: false | |
}; | |
loadImage = src => { | |
this.setState({ isLoading: true }); | |
let img = new Image(); | |
img.onload = () => { | |
this.setState({ isLoading: false }); | |
}; | |
img.src = src; | |
}; | |
componentDidMount() { | |
this.loadImage(this.props.url); | |
} | |
componentWillReceiveProps(nextProps) { | |
this.loadImage(nextProps.url); | |
} | |
render() { | |
return ( | |
<div> | |
{this.state.isLoading ? ( | |
<p>Загружаю...</p> | |
) : ( | |
<img src={this.props.url} alt={"name-pic"} /> | |
)} | |
</div> | |
); | |
} | |
} | |
const IMGS_DATA = { | |
Picture1: | |
"http://dl3.joxi.net/drive/2018/07/24/0027/1686/1799830/30/32635ae563.jpg", | |
Picture2: | |
"http://dl3.joxi.net/drive/2018/07/24/0027/1686/1799830/30/03f67e52ae.jpg", | |
Picture3: | |
"http://dl3.joxi.net/drive/2018/07/24/0027/1686/1799830/30/18640951d3.jpg", | |
Picture4: | |
"http://dl3.joxi.net/drive/2018/07/24/0027/1686/1799830/30/0bf7d53c53.jpg", | |
Picture5: | |
"http://dl3.joxi.net/drive/2018/07/24/0027/1686/1799830/30/d4e6940379.jpg", | |
Picture6: | |
"http://dl3.joxi.net/drive/2018/07/24/0027/1686/1799830/30/9e3e011887.jpg", | |
Picture7: | |
"http://dl3.joxi.net/drive/2018/07/24/0027/1686/1799830/30/3a8339df21.jpg", | |
Picture8: | |
"http://dl4.joxi.net/drive/2018/07/24/0027/1686/1799830/30/184fe0fa97.jpg", | |
start: | |
"http://dl3.joxi.net/drive/2018/07/24/0027/1686/1799830/30/18b3c12c33.jpg" | |
}; | |
class App extends Component { | |
state = { | |
name: IMGS_DATA.start | |
}; | |
readUrl = e => { | |
this.setState({ | |
name: IMGS_DATA[e.currentTarget.dataset.name] | |
}); | |
}; | |
render() { | |
return ( | |
<div className="App"> | |
<header className="App-header"> | |
<h1 className="App-title"> | |
Спаси принцессу - выбери язык програмирования:) | |
</h1> | |
</header> | |
<div className="buttons"> | |
<button data-name="Picture1" onClick={this.readUrl}> | |
JavaScript | |
</button>{" "} | |
<button data-name="Picture2" onClick={this.readUrl}> | |
C | |
</button>{" "} | |
<button data-name="Picture3" onClick={this.readUrl}> | |
Java | |
</button>{" "} | |
<button data-name="Picture4" onClick={this.readUrl}> | |
Lisp | |
</button>{" "} | |
<button data-name="Picture5" onClick={this.readUrl}> | |
C# | |
</button>{" "} | |
<button data-name="Picture6" onClick={this.readUrl}> | |
Go | |
</button>{" "} | |
<button data-name="Picture7" onClick={this.readUrl}> | |
Pascal | |
</button>{" "} | |
<button data-name="Picture8" onClick={this.readUrl}> | |
PHP | |
</button>{" "} | |
</div> | |
<Pic url={this.state.name} /> | |
</div> | |
); | |
} | |
} | |
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from "react"; | |
class VideoPlayer extends Component { | |
video = React.createRef(); | |
// | |
playVideo = e => { | |
this.video.current.play(); | |
}; | |
stopVideo = e => { | |
this.video.current.pause(); | |
}; | |
render() { | |
return ( | |
<div className="video-player"> | |
<video | |
className="video-player__source" | |
src={videoFile} | |
ref={this.video} | |
/> | |
<nav> | |
<button className="btn-play" onClick={this.playVideo}> | |
Play | |
</button> | |
<button className="btn-stop" onClick={this.stopVideo}> | |
Stop | |
</button> | |
</nav> | |
</div> | |
); | |
} | |
} | |
class App extends Component { | |
render() { | |
return <VideoPlayer />; | |
} | |
} | |
export default App; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from 'react'; | |
import AppHeader from '../app-header'; | |
import TodoList from '../todo-list'; | |
import SearchPanel from '../search-panel'; | |
import ItemStatusFilter from '../item-status-filter'; | |
import ItemAddForm from '../item-add-form'; | |
import './app.css'; | |
export default class App extends Component { | |
maxId = 100; | |
state = { | |
items: [ | |
{ id: 1, label: 'Drink Coffee', important: false, done: false }, | |
{ id: 2, label: 'Learn React', important: true, done: false }, | |
{ id: 3, label: 'Make Awesome App', important: false, done: false } | |
], | |
filter: 'all', | |
search: '' | |
}; | |
onItemAdded = (label) => { | |
this.setState((state) => { | |
const item = this.createItem(label); | |
return { items: [...state.items, item] }; | |
}) | |
}; | |
toggleProperty = (arr, id, propName) => { | |
const idx = arr.findIndex((item) => item.id === id); | |
const oldItem = arr[idx]; | |
const value = !oldItem[propName]; | |
const item = { ...arr[idx], [propName]: value } ; | |
return [ | |
...arr.slice(0, idx), | |
item, | |
...arr.slice(idx + 1) | |
]; | |
}; | |
onToggleDone = (id) => { | |
this.setState((state) => { | |
const items = this.toggleProperty(state.items, id, 'done'); | |
return { items }; | |
}); | |
}; | |
onToggleImportant = (id) => { | |
this.setState((state) => { | |
const items = this.toggleProperty(state.items, id, 'important'); | |
return { items }; | |
}); | |
}; | |
onDelete = (id) => { | |
this.setState((state) => { | |
const idx = state.items.findIndex((item) => item.id === id); | |
const items = [ | |
...state.items.slice(0, idx), | |
...state.items.slice(idx + 1) | |
]; | |
return { items }; | |
}); | |
}; | |
onFilterChange = (filter) => { | |
this.setState({ filter }); | |
}; | |
onSearchChange = (search) => { | |
this.setState({ search }); | |
}; | |
createItem(label) { | |
return { | |
id: ++this.maxId, | |
label, | |
important: false, | |
done: false | |
}; | |
} | |
filterItems(items, filter) { | |
if (filter === 'all') { | |
return items; | |
} else if (filter === 'active') { | |
return items.filter((item) => (!item.done)); | |
} else if (filter === 'done') { | |
return items.filter((item) => item.done); | |
} | |
} | |
searchItems(items, search) { | |
if (search.length === 0) { | |
return items; | |
} | |
return items.filter((item) => { | |
return item.label.toLowerCase().indexOf(search.toLowerCase()) > -1; | |
}); | |
} | |
render() { | |
const { items, filter, search } = this.state; | |
const doneCount = items.filter((item) => item.done).length; | |
const toDoCount = items.length - doneCount; | |
const visibleItems = this.searchItems(this.filterItems(items, filter), search); | |
return ( | |
<div className="todo-app"> | |
<AppHeader toDo={toDoCount} done={doneCount}/> | |
<div className="search-panel d-flex"> | |
<SearchPanel | |
onSearchChange={this.onSearchChange}/> | |
<ItemStatusFilter | |
filter={filter} | |
onFilterChange={this.onFilterChange} /> | |
</div> | |
<TodoList | |
items={ visibleItems } | |
onToggleImportant={this.onToggleImportant} | |
onToggleDone={this.onToggleDone} | |
onDelete={this.onDelete} /> | |
<ItemAddForm | |
onItemAdded={this.onItemAdded} /> | |
</div> | |
); | |
}; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from "react"; | |
// Пример простого приложения React | |
// Он использует простые компоненты для своих компонентов без состояния | |
// и сложный класс компонентов для обработки взаимодействий | |
// Сначала у нас есть Task и TaskList | |
// Они получают все свои данные/состояние через свои свойства | |
// <TaskList> | |
// <Task text="Сделать что-нибудь" /> | |
// <Task text="Ничего не делать" /> | |
// </TaskList> | |
// Task требует свойства text | |
const Task = props => { | |
return <li>{props.text}</li>; | |
}; | |
// TaskList нужен в массиве Task в свойстве children | |
const TaskList = props => { | |
// Вывод первого элемента жирным шрифтом | |
return ( | |
<ul> | |
<b key={0}>{props.children[0]}</b> | |
{props.children.slice(1)} | |
</ul> | |
); | |
}; | |
// Этот компонент обрабатывает поле ввода | |
// Он должен быть классом, поскольку элемент <input> имеет состояние | |
class TaskInput extends Component { | |
state = { value: "" }; | |
// вызывается, когда кто-то вводит в элемент <input> | |
handleChange = e => { | |
this.setState({ value: e.target.value }); | |
}; | |
// вызывается, когда кто-то нажимает на элемент <button> | |
handleAdd = e => { | |
if (!this.state.value) return; | |
// вызвать функцию, которая была передана в ее свойство onAdd | |
this.props.onAdd(this.state.value); | |
// очистить состояние, чтобы поле ввода снова было пустым после добавления | |
this.setState({ value: "" }); | |
}; | |
// renders the elements every time someone types or adds | |
render() { | |
return ( | |
<div> | |
<input | |
className="form-control" | |
placeholder="Enter Task ." | |
value={this.state.value} | |
onChange={this.handleChange} | |
/> | |
<button className="btn btn-success" onClick={this.handleAdd}> | |
Add | |
</button> | |
</div> | |
); | |
} | |
} | |
// Приложение отслеживает текущие задачи в своём состоянии | |
class TodoApp extends Component { | |
state = { tasks: [] }; | |
// Этот колбэк будет передан в свойство onAdd компонента <TaskInput> | |
handleAdd = task => { | |
// Добавление новой задачи | |
const tasks = [task].concat(this.state.tasks); | |
// это заставляет отрисовать компонент <TodoApp> | |
this.setState({ tasks: tasks }); | |
}; | |
render() { | |
// Создать список компонентов <Task> из массива задач в состоянии | |
// простая стилизация | |
// и добавление обработчика добавления к компоненту <TaskInput> | |
return ( | |
<div style={{ width: 300, margin: "auto" }}> | |
<TaskInput onAdd={this.handleAdd} /> | |
<TaskList> | |
{this.state.tasks.map((t, i) => { | |
return <Task key={i} text={t} />; | |
})} | |
</TaskList> | |
</div> | |
); | |
} | |
} | |
class App extends Component { | |
render() { | |
return <TodoApp />; | |
} | |
} | |
export default App; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment