Задать вопрос
@gsdev99

Как исправить ошибку в своей реализации redux?

Всем привет. У меня не есть самостоятельная реализация redux (разбираюсь с чужим кодом). И у меня возникла следующая проблема.
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';

// Начну по порядку. Ниже приведены функции createStore, connect, Provider

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() {
        console.log('componentDidUpdate()')
        this.context.store.subscribe(this.handleChange)
      }

      handleChange = () => {
        console.log('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,
}

// Ниже приведены actions, action creators, reducers

// 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,
        currentInterval: state.currentInterval + action.payload
      }

    default:
      return state
  }
}

// Далее компонент, которые будет отрендерен

class IntervalComponent extends React.Component {
  render() {
    console.log('render()')
    console.log(this.props)

    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((state) => ({
    currentInterval: state,
    // currentInterval: state.currentInterval,
  }),
  dispatch => ({
    changeInterval: value => dispatch(changeInterval(value))
  }))(IntervalComponent)


// init
ReactDOM.render(
  <Provider store={createStore(reducer)}>
    <Interval />
  </Provider>,
  document.getElementById('root')
)


В данном примере очевидная проблема, что не передается initialState
Что сделал я: в reducer дописал: state = initialState, ну и конечно описал initialState
const initialState = {
  currentInterval: 3000
}

// reducers
const reducer = (state = initialState, action) => {
  console.log('state', state)
  console.log('action', action)

  switch(action.type) {
    case CHANGE_INTERVAL:
      return {
        ...state,
        currentInterval: state.currentInterval + action.payload
      }

    default:
      return state
  }
}

Остались две проблемы:
- initialState нет при инициализации компонента
- И когда reducer обновляет состояние, не происходит render IntervalComponent, соответственно визуально ничего не меняется.
Буду благодарен любой помощи.
https://codepen.io/gsdev99/pen/pYqmRr
  • Вопрос задан
  • 292 просмотра
Подписаться 1 Простой 1 комментарий
Пригласить эксперта
Ответы на вопрос 1
@bini1988
Redux диспатчит initial action при первом создании стора, передавая undefined в редюсер и специальный экшн {type: "INIT" }. Второй момент, думаю подписка на стор должна быть в componentDidMount, так же можно добавить отписку от стора в componentWillUnmont для удаления лишних кобэков.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы