Skip to content

Instantly share code, notes, and snippets.

@Dmitriy-8-Kireev
Last active December 8, 2018 17:20
Show Gist options
  • Save Dmitriy-8-Kireev/fd2db090d4fc34a949a1a84138f27d5c to your computer and use it in GitHub Desktop.
Save Dmitriy-8-Kireev/fd2db090d4fc34a949a1a84138f27d5c to your computer and use it in GitHub Desktop.
Набор универсальных фун-ий в app.js
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;
Дополнительный вариант
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"; более простой вариант
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;
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;
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>
);
};
}
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