TTATPuOT
@TTATPuOT
https://code.patriotovsky.ru/

Почему в React не обновляется props компонента при изменении хранилища Redux в другом компоненте?

Здравствуйте!
Начал изучать Redux для React. Сразу столкнулся с проблемой общих данных для разных компонентов. Привожу пример кода, который у меня не работает:
Изначально, есть файл index.js, где создано хранилище redux и передано через Provider во все компоненты:
<Provider store={this.state.store}>
    <Header />
    <Body />
    //Здесь ещё другие компоненты
</Provider>

Далее, в компоненте Header я пытаюсь в методе render получить текущие состояние props:
class Header extends React.Component {
    render() {
        console.log(JSON.stringify(this.props.store));
        return ('');
    }
}
export default connect(
    store => ({
        store: store
    })
)(Header);

Но в консоли выводится лишь начальное состояние хранилища, а не то, которое я задал в другом компоненте. Если состояние хранилища обновить из другого компонента - то в другом компоненте можно увидеть обновление хранилища, а в Header всё так же будут старые начальные данные.

Пример обновления хранилища из другого компонента:
class Body extends React.Component {
	componentDidMount() {
		setTimeout(() => {
			updateStore(1);
		});
	}
    render() {
        console.log(JSON.stringify(this.props.store));
        return ('');
    }
}

export default connect(
    store => ({
        store: store
    }),
    dispatch => ({
    	updateStore: (i) => {
    		dispatch({type: 'new', store: i});
    	}
    })
)(Body);

Полагаю, ошибка в чём-то банальном.

Заранее спасибо.
  • Вопрос задан
  • 3652 просмотра
Решения вопроса 1
TTATPuOT
@TTATPuOT Автор вопроса
https://code.patriotovsky.ru/
Спасибо. Но решение было в том, что в reducer'е нужно возвращать новый объект state, а не старый, который передан в аргументах функции. А reducer я как раз таки и не опубликовал.
На всякий случай вот НЕПРАВИЛЬНЫЙ УЧАСТОК КОДА:
function reducer(state = initialState, action) {
    if (action.type === 'new') {
        state.playload = action.playload;
    }
    return state;
}
const store = createStore(reducer);


Должно быть вот так:
function reducer(state = initialState, action) {
    if (action.type === 'new') {
        return Object.assign({}, state, {
            playload: action.playload
        })
    }
    return state;
}
const store = createStore(reducer);

Грубо говоря, каждый раз нужно возвращать не тот state который был передан в reducer, а новый. Если речь не идёт о примитивах, о чём правильно заметили в комментариях.
Спасибо всем за ответы.
Ответ написан
Пригласить эксперта
Ответы на вопрос 3
@grinat
Насколько помню там надо доп функцию подключать, которая вызывается при изменении state и через нее мутировать пропсы внутри компонента. Тут шо то ее не видно.
Ответ написан
Комментировать
а где ты сам store создал? что это ты такое в провайдер запихнул?
Ответ написан
rockon404
@rockon404 Куратор тега React
Frontend Developer
Трудно что-то сказать, так как вы предоставили в примерах либо недостоверный, либо нерабочий код:
componentDidMount() {
  setTimeout(() => {
    updateStore(1); // <--- WTF?
  });
}


Вот полностью рабочий пример кода, повторяющий логику вашего:
import React, { useRef, useCallback } from 'react';
import ReactDOM from 'react-dom';
import { Provider, connect } from 'react-redux';
import { createStore } from 'redux';

const UPDATE = 'UPDATE';

const update = (payload) => ({
  type: UPDATE,
  payload,
});

const reducer = (state = 0, action) => {
  if (action.type === UPDATE) {
    return action.payload;
  }
  return state;
}

const store = createStore(reducer);

const mapStateToProps = state => ({ state });

const  mapDispatchToProps = { update };

const Header = ({ state }) => (
  <div>Header. State: {state}</div>
);

const ConnectedHeader = connect(mapStateToProps)(Header);

const Body = ({ state, update }) => {
  const inputEl = useRef(null);
  const handler = useCallback(() => {
    update(inputEl.current.value);
  }, [inputEl, update]);

  return (
    <div>
      <div>Body. State: {state}</div>
      <input type="number" ref={inputEl} />
      <button onClick={handler}>Update state</button>
    </div>
  );
}

const ConnectedBody = connect(
  mapStateToProps,
  mapDispatchToProps,
)(Body);

const App = () => (
  <Provider store={store}>
    <ConnectedHeader />
    <ConnectedBody />
  </Provider>
);

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Демо
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы