Skip to content

Instantly share code, notes, and snippets.

@DonkovtsevArthur
Created August 14, 2020 07:51
Show Gist options
  • Save DonkovtsevArthur/5d84a4049903b4cb50640a9cd6ab69c1 to your computer and use it in GitHub Desktop.
Save DonkovtsevArthur/5d84a4049903b4cb50640a9cd6ab69c1 to your computer and use it in GitHub Desktop.
Slomux
<div id="app" />
// Slomux — упрощённая, сломанная реализация Flux.
// Перед вами небольшое приложение, написанное на React + Slomux.
// Это нерабочий секундомер с настройкой интервала обновления.
// Исправьте ошибки и потенциально проблемный код, почините приложение и прокомментируйте своё решение.
// При нажатии на "старт" должен запускаться секундомер и через заданный интервал времени увеличивать свое значение на значение интервала
// При нажатии на "стоп" секундомер должен останавливаться и сбрасывать свое значение
const createStore = (reducer, initialState) => {
let currentState = initialState
const listeners = []
const getState = () => currentState
const dispatch = action => {
currentState = reducer(currentState, action)
listeners.forEach(listener => listener())
}
const subscribe = listener => listeners.push(listener)
return { getState, dispatch, subscribe }
}
const connect = (mapStateToProps, mapDispatchToProps) =>
Component => {
class WrappedComponent extends React.Component {
render() {
return (
<Component
{...this.props}
{...mapStateToProps(this.context.store.getState(), this.props)}
{...mapDispatchToProps(this.context.store.dispatch, this.props)}
/>
)
}
componentDidUpdate() {
this.context.store.subscribe(this.handleChange)
}
handleChange = () => {
this.forceUpdate()
}
}
WrappedComponent.contextTypes = {
store: PropTypes.object,
}
return WrappedComponent
}
class Provider extends React.Component {
getChildContext() {
return {
store: this.props.store,
}
}
render() {
return React.Children.only(this.props.children)
}
}
Provider.childContextTypes = {
store: PropTypes.object,
}
// APP
// actions
const CHANGE_INTERVAL = 'CHANGE_INTERVAL'
// action creators
const changeInterval = value => ({
type: CHANGE_INTERVAL,
payload: value,
})
// reducers
const reducer = (state, action) => {
switch(action.type) {
case CHANGE_INTERVAL:
return state += action.payload
default:
return {}
}
}
// components
class IntervalComponent extends React.Component {
render() {
return (
<div>
<span>Интервал обновления секундомера: {this.props.currentInterval} сек.</span>
<span>
<button onClick={() => this.props.changeInterval(-1)}>-</button>
<button onClick={() => this.props.changeInterval(1)}>+</button>
</span>
</div>
)
}
}
const Interval = connect(dispatch => ({
changeInterval: value => dispatch(changeInterval(value)),
}),
state => ({
currentInterval: state,
}))(IntervalComponent)
class TimerComponent extends React.Component {
state = {
currentTime: 0
}
render() {
return (
<div>
<Interval />
<div>
Секундомер: {this.state.currentTime} сек.
</div>
<div>
<button onClick={this.handleStart}>Старт</button>
<button onClick={this.handleStop}>Стоп</button>
</div>
</div>
)
}
handleStart() {
setTimeout(() => this.setState({
currentTime: this.state.currentTime + this.props.currentInterval,
}), this.props.currentInterval)
}
handleStop() {
this.setState({ currentTime: 0 })
}
}
const Timer = connect(state => ({
currentInterval: state,
}), () => {})(TimerComponent)
// init
ReactDOM.render(
<Provider store={createStore(reducer)}>
<Timer />
</Provider>,
document.getElementById('app')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.7.2/prop-types.min.js"></script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment