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, соответственно визуально ничего не меняется.
Буду благодарен любой помощи.
Если даже написать action для получения данных при инициализации компонента, то не происходит вызова render в компоненте при изменении store:
codepen.io/gsdev99/pen/pYqmRr
Сообщение отредактировал Rohviktor: 12 Август 2019 - 05:48