Как исправить ошибку в своей реализации 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 |
const initialState = { currentInterval: 3000 } const createStore = (reducer, initialState) => { let currentState = initialState const listeners = [] console.log('currentState', currentState) 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)} /> ) } componentDidMount() { console.log('WRAPPEDCOMPONENT DID MOUNT') this.context.store.subscribe(this.handleChange) } // 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() { console.log('getChildContext, store', this.props.store) return { store: this.props.store, } } render() { return React.Children.only(this.props.children) } } Provider.childContextTypes = { store: PropTypes.object, } // actions const FETCH_INITIAL_STATE = 'FETCH_INITIAL_STATE' const CHANGE_INTERVAL = 'CHANGE_INTERVAL' // action creators const fetchInitialState = () => ({ type: FETCH_INITIAL_STATE }) const changeInterval = value => ({ type: CHANGE_INTERVAL, payload: value, }) // reducers const reducer = (state, action) => { console.log('state', state) console.log('action', action) switch (action.type) { case FETCH_INITIAL_STATE: return state case CHANGE_INTERVAL: console.log('CHANGE_INTERVAL', state, action) const nextState = { ...state, currentInterval: state.currentInterval + action.payload, } console.log('nextState', nextState, 'ok') return nextState default: return state } } // components class IntervalComponent extends React.Component { componentDidMount() { console.log('componentDidMount()') this.props.fetchInitialState() console.log('props', this.props) } 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, // currentInterval: state.currentInterval, }), dispatch => ({ changeInterval: value => dispatch(changeInterval(value)), fetchInitialState: value => dispatch(fetchInitialState()), }))(IntervalComponent) const str = createStore(reducer, initialState) // init ReactDOM.render( <Provider store={str}> <Interval/> </Provider>, document.getElementById('root') ) ) что-то получилось... 1) inititalState ты не правильно передавал, тк createStore уже ждет initialState 2) потом неправильный объект был 3) и напоследок, не там стоял подписчик... |
Спасибо тебе большое!
|
Часовой пояс GMT +3, время: 20:09. |