Как мне получить доступ к состоянию хранилища в React Redux?

86

Я просто делаю простое приложение для изучения асинхронности с помощью redux. У меня все заработало, теперь я просто хочу отобразить фактическое состояние на веб-странице. Теперь, как мне получить доступ к состоянию магазина в методе рендеринга?

Вот мой код (все на одной странице, потому что я только учусь):

const initialState = {
        fetching: false,
        fetched: false,
        items: [],
        error: null
    }

const reducer = (state=initialState, action) => {
    switch (action.type) {
        case "REQUEST_PENDING": {
            return {...state, fetching: true};
        }
        case "REQUEST_FULFILLED": {
            return {
                ...state,
                fetching: false,
                fetched: true,
                items: action.payload
            }
        }
        case "REQUEST_REJECTED": {
            return {...state, fetching: false, error: action.payload}   
        }
        default: 
            return state;
    }
};

const middleware = applyMiddleware(promise(), thunk, logger());
const store = createStore(reducer, middleware);

store.dispatch({
    type: "REQUEST",
    payload: fetch('http://localhost:8000/list').then((res)=>res.json())
});

store.dispatch({
    type: "REQUEST",
    payload: fetch('http://localhost:8000/list').then((res)=>res.json())
});

render(
    <Provider store={store}>
        <div>
            { this.props.items.map((item) => <p> {item.title} </p> )}
        </div>
    </Provider>,
    document.getElementById('app')
);

Итак, в методе рендеринга состояния я хочу вывести все item.titleиз магазина.

благодаря

Паркизм
источник
5
Вы почти у цели. Вам необходимо создать компонент, подключенный к магазину, с помощью react-reduxбиблиотеки. Я настоятельно рекомендую вам улучшить свое понимание redux с помощью бесплатного курса автора: egghead.io/courses/getting-started-with-redux
ctrlplusb
3
Вы store.getState()действительно читаете состояние из вашего магазина. redux.js.org/docs/api/Store.html#getState
Кенни Уорден,
2
Спасибо за руководство. Я не совсем понимаю redux, и этот урок мне очень поможет.
Parkicism

Ответы:

64

Вы должны создать отдельный компонент, который будет прослушивать изменения состояния и обновляться при каждом изменении состояния:

import store from '../reducers/store';

class Items extends Component {
  constructor(props) {
    super(props);

    this.state = {
      items: [],
    };

    store.subscribe(() => {
      // When state will be updated(in our case, when items will be fetched), 
      // we will update local component state and force component to rerender 
      // with new data.

      this.setState({
        items: store.getState().items;
      });
    });
  }

  render() {
    return (
      <div>
        {this.state.items.map((item) => <p> {item.title} </p> )}
      </div>
    );
  }
};

render(<Items />, document.getElementById('app'));
1вен
источник
61
@ 1ven как storeопределить здесь переменную?
Bang Dao
3
@BangDao мы можем предположить, что мы импортируем его из внешнего файла. storeпеременная - это экземпляр хранилища redux.
сен
28
@BangDao Вы должны включить storeимпорт для ясности.
Kurai Bankusu 06
5
ReferenceError Не могу найти переменную: магазин
Пит Элвин
4
import store from '../reducers/store';. и store.jsбудет содержатьconst createStoreWithMiddleware = applyMiddleware(thunkMiddleware,promise)(createStore); export default createStoreWithMiddleware(reducers);
AnBisw
45

Импортировать connectиз react-reduxи использовать его для связи компонента с состояниемconnect(mapStates,mapDispatch)(component)

import React from "react";
import { connect } from "react-redux";


const MyComponent = (props) => {
    return (
      <div>
        <h1>{props.title}</h1>
      </div>
    );
  }
}

Наконец, вам нужно сопоставить состояния с реквизитами, чтобы получить к ним доступ с помощью this.props

const mapStateToProps = state => {
  return {
    title: state.title
  };
};
export default connect(mapStateToProps)(MyComponent);

Только те штаты, которые вы отображаете, будут доступны через props

Посмотрите этот ответ: https://stackoverflow.com/a/36214059/4040563

Для дальнейшего чтения: https://medium.com/@atomarranger/redux-mapstatetoprops-and-mapdispatchtoprops-shorthand-67d6cd78f132

Захер Масри
источник
1
ПРИМЕЧАНИЕ. Таким образом, свойства не будут доступны без вызова действия (определенного в mapDispatchToProps). Если вы пытаетесь получить то, что уже есть в магазине, не отправляя еще один цикл выборки, вам придется использовать либо subscribeлибо getStateна store.
AnBisw
13

Вам нужно использовать, Store.getState()чтобы узнать текущее состояние вашего Магазина.

Для получения дополнительной информации о getState()просмотре этого короткого видео.

Semanser
источник
Так что я просто перейду this.props.itemsна store.getState().items? Когда я это сделал, он не выводил item.title.
Parkicism
1
@Parkicism выглядит так, будто вы не выполняли первоначальный рендеринг для своего компонента. Я настоятельно рекомендую вам посмотреть этот курс: egghead.io/courses/getting-started-with-redux
semanser
1
@Parkicism - это не отображение элементов, потому что, когда приложение выполняет рендеринг в первый раз, ответ от сервера еще не получен, вам нужно подписаться на хранилище, чтобы обновлять компонент каждый раз, когда хранилище изменяется.
1вн,
У меня есть let store = createStore(todoApp);внутри, index.jsи я хочу получить доступ storeвнутрь App.js- как это сделать?
N Sharma
TypeError: undefined не является объектом (оценивается _redux.Store.getState)
Пит Алвин,
6

Вы хотите сделать больше, чем просто getState. Вы хотите реагировать на изменения в магазине.

Если вы не используете response-redux, вы можете сделать это:

function rerender() {
    const state = store.getState();
    render(
        <div>
            { state.items.map((item) => <p> {item.title} </p> )}
        </div>,
        document.getElementById('app')
    );
}

// subscribe to store
store.subscribe(rerender);

// do initial render
rerender();

// dispatch more actions and view will update

Но лучше использовать react-redux. В этом случае вы используете Provider, как вы упомянули, но затем используете connect для подключения вашего компонента к магазину.

Брэндон
источник
6
Операция просила специально для React-Redux. Зачем предлагать решение для чего-то другого, кроме запроса?
Kermit_ice_tea
ReferenceError Не могу найти переменную: магазин
Пит Элвин
3

Если вы хотите выполнить мощную отладку, вы можете подписаться на каждое изменение состояния и приостановить приложение, чтобы подробно узнать, что происходит, следующим образом.

store.js
store.subscribe( () => {
  console.log('state\n', store.getState());
  debugger;
});

Поместите это в файл, где вы это делаете createStore.

Чтобы скопировать stateобъект из консоли в буфер обмена, выполните следующие действия:

  1. Щелкните правой кнопкой мыши объект в консоли Chrome и выберите «Сохранить как глобальную переменную» в контекстном меню. В качестве имени переменной он вернет что-то вроде temp1.

  2. У Chrome также есть copy()метод, поэтому copy(temp1)в консоли следует скопировать этот объект в буфер обмена.

https://stackoverflow.com/a/25140576

https://scottwhittaker.net/chrome-devtools/2016/02/29/chrome-devtools-copy-object.html

Вы можете просмотреть объект в программе просмотра json, например: http://jsonviewer.stack.hu/

Здесь вы можете сравнить два объекта json: http://www.jsondiff.com/

Позвольте мне подумать об этом
источник
тоже хорошая статья coderwall.com/p/pafnew/redux-middleware-logger
zloctb