Skip to content

Instantly share code, notes, and snippets.

@Dmitriy-8-Kireev
Created December 15, 2018 16:48
Show Gist options
  • Save Dmitriy-8-Kireev/98d46e232a425cffa5cab17e6d5e62b5 to your computer and use it in GitHub Desktop.
Save Dmitriy-8-Kireev/98d46e232a425cffa5cab17e6d5e62b5 to your computer and use it in GitHub Desktop.
// INDEX.JS
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import AppRouter from 'components/AppRouter';
import getStore from './store';
import { Provider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
const store = getStore();
ReactDOM.render(
<BrowserRouter basename="/search-serials">
<Provider store={store}>
<AppRouter />
</Provider>
</BrowserRouter>,
document.getElementById('root')
);
//
//API.JS
//
xport const search = query =>
fetch(`http://api.tvmaze.com/search/shows?q=${query}`, {
method: 'GET',
mode: 'cors',
})
.then(response => response.json())
.then(shows => shows.map(show => show.show));
export const show = showId =>
fetch(`http://api.tvmaze.com/shows/${showId}?embed=cast`, {
method: 'GET',
mode: 'cors',
}).then(response => response.json());
//
//STORE.JS
//
import { createStore, applyMiddleware, compose } from 'redux';
import rootReducer from './reducers';
import showMiddleware from './middlewares/showMiddleware';
import searchMiddleware from './middlewares/searchMiddleware';
export default initialState =>
createStore(
rootReducer,
initialState,
compose(
applyMiddleware(searchMiddleware, showMiddleware),
window.devToolsExtension ? window.__REDUX_DEVTOOLS_EXTENSION__() : f => f,
),
);
//SRC
//ACTIONS
//searchActions.js
import { createActions } from 'redux-actions';
export const { searchRequest, searchSuccess, searchFailure } = createActions({
SEARCH_REQUEST: undefined,
SEARCH_SUCCESS: undefined,
SEARCH_FAILURE: undefined
});
//SRC
//ACTIONS
//showActions.js
import { createActions } from 'redux-actions';
export const { showRequest, showSuccess, showFailure } = createActions(
'SHOW_REQUEST',
'SHOW_SUCCESS',
'SHOW_FAILURE'
);
//SRC
//MIDDLEWARES
//searchMiddleware.js
import { search } from '../api';
import {
searchRequest,
searchSuccess,
searchFailure
} from '../actions/searchActions';
export default store => next => action => {
if (action.type === searchRequest.toString()) {
const query = action.payload;
search(query)
.then(series => {
store.dispatch(searchSuccess(series));
})
.catch(e => {
store.dispatch(searchFailure(e.toString()));
});
}
return next(action);
};
//SRC
//MIDDLEWARES
//showMiddleware.js
import { showRequest, showSuccess, showFailure } from '../actions/showActions';
import { show } from '../api';
export default store => next => action => {
if (action.type === showRequest.toString()) {
show(action.payload)
.then(entities => {
store.dispatch(showSuccess(entities));
})
.catch(error => {
store.dispatch(showFailure(error));
});
}
return next(action);
};
//SRC
//REDUCERS
//index.js
import { combineReducers } from 'redux';
import search from './search';
import shows from './shows';
export default combineReducers({
search,
shows,
});
//SRC
//REDUCERS
//search.js
import {
searchRequest,
searchSuccess,
searchFailure
} from '../actions/searchActions';
import { combineReducers } from 'redux';
import { handleAction } from 'redux-actions';
const films = handleAction(
searchSuccess,
(state, action) => action.payload,
[]
);
const error = handleAction(
searchFailure,
(state, action) => action.error,
null
);
const isFetching = (state = false, action: payloadAction): boolean => {
switch (action.type) {
case searchRequest:
return true;
case searchSuccess:
return false;
case searchFailure:
return false;
default:
return state;
}
};
const isFetched = (state = false, action: payloadAction): boolean => {
switch (action.type) {
case searchRequest:
return false;
case searchSuccess:
return true;
case searchFailure:
return true;
default:
return state;
}
};
export default combineReducers({
error,
films,
isFetched,
isFetching
});
export const getfilms = state => state.films;
export const getIsFetching = state => state.isFetching;
export const getIsFetched = state => state.isFetched;
export const getError = state => state.error;
//SRC
//REDUCERS
//shows.js
import { showRequest, showSuccess, showFailure } from '../actions/showActions';
import { combineReducers } from 'redux';
import { handleAction } from 'redux-actions';
const show = handleAction(showSuccess, (state, action) => action.payload, []);
const error = handleAction(showFailure, (state, action) => action.error, null);
const isFetching = (state = false, action: payloadAction): boolean => {
switch (action.type) {
case showRequest:
return true;
case showSuccess:
return false;
case showFailure:
return false;
default:
return state;
}
};
const isFetched = (state = false, action: payloadAction): boolean => {
switch (action.type) {
case showRequest:
return false;
case showSuccess:
return true;
case showFailure:
return true;
default:
return state;
}
};
export default combineReducers({
error,
show,
isFetched,
isFetching
});
export const getShow = state => state.show;
export const getIsFetching = state => state.isFetching;
export const getIsFetched = state => state.isFetched;
export const getError = state => state.error;
//SRC
//COMPONENTS
//AppRouter.js используется вместе с index.js export { default } from './AppRouter';
import React, { Component } from 'react';
import './AppRouter.css';
import { Route, Switch, withRouter } from 'react-router-dom';
import Search from 'components/Search';
import ShowPage from 'components/ShowPage';
class AppRouter extends Component {
render() {
return (
<div className="App">
<Switch>
<Route exact path="/" component={Search} />
<Route path="/shows/:id" component={ShowPage} />
</Switch>
</div>
);
}
}
export default withRouter(AppRouter);
//SRC
//COMPONENTS
//Search.js используется вместе с index.js export { default } from './Search';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { searchRequest } from '../../actions/searchActions';
import ShowPreview from '../ShowPreview/ShowPreview';
class Search extends Component {
constructor(props) {
super(props);
this.state = { searchInput: '' };
}
hanleInputChange = e => {
const { name, value } = e.target;
this.setState({ [name]: value });
};
handleSearch = () => {
this.props.searchRequest(this.state.searchInput);
};
render() {
const { isFetching, films } = this.props;
const { searchInput } = this.state;
return (
<div className="Search">
<div className="SearchForm">
<input
type="text"
placeholder="Название сериала"
name="searchInput"
value={searchInput}
onChange={this.hanleInputChange}
/>
<button onClick={this.handleSearch}>Найти</button>
</div>
<div className="SearсhResult">
{isFetching ? (
<div>
<p>Загрузка...</p>
</div>
) : (
<ul>
{films.map(film => (
<article className="results-item" key={film.id}>
<h3>
<Link to={`/shows/${film.id}`}>{film.name}</Link>
</h3>
{films.map(({ id, name, image, summary }) => (
<ShowPreview
key={id}
id={id}
name={name}
image={image}
summary={summary}
/>
))}
</article>
))}
</ul>
)}
</div>
</div>
);
}
}
const mapStateToProps = state => ({
isFetching: state.search.isFetching,
films: state.search.films
});
const mapDispatchToProps = {
searchRequest
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(Search);
//SRC
//COMPONENTS
//ShowPage.js используется вместе с index.js export { default } from './ShowPage'
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { showRequest } from '../../actions/showActions';
export class ShowPage extends Component {
constructor(props) {
super(props);
this.props.showRequest(this.props.match.params.id);
}
render() {
const { isFetching, show } = this.props;
return (
<div className="ShowPage">
{isFetching ? (
<div>
<p>Загрузка...</p>
</div>
) : (
<div>
<div className="ShowPage_title" key={show.id}>
{show.name}
<br />
{show.image && <img src={show.image.medium} alt={show.name} />}
<br />
{show._embedded &&
show._embedded.cast &&
show._embedded.cast.map(this.Person)}
</div>
</div>
)}
</div>
);
}
Person = ({ person }) => (
<div className="ShowPage_persons" key={person.id}>
{person.name}
<br />
{person.image && <img src={person.image.medium} alt={person.name} />}
</div>
);
}
const mapStateToProps = state => ({
isFetching: state.shows.isFetching,
show: state.shows.show
});
const mapDispatchToProps = {
showRequest
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(ShowPage);
//SRC
//COMPONENTS
//ShowPreview.js используется вместе с index.js export { default } from './ShowPreview';
import React, { PureComponent } from 'react';
import { Link } from 'react-router-dom';
export default class ShowPreview extends PureComponent {
render() {
const { id, name, image, summary } = this.props;
return (
<li className="serial" key={id}>
<Link className="serial__link" to={`/shows/${id}`}>
{name}
</Link>
{image && <img className="serial__img" src={image.medium} alt={name} />}
<div
className="serial__summary"
dangerouslySetInnerHTML={{ __html: summary }}
/>
</li>
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment