Как использовать React-redux, чтобы избежать локального состояния в моем коде? - PullRequest
0 голосов
/ 29 марта 2019

Я изучаю избыточность, и я написал простой код, который использует хранилище, действие и редуктор.Я использую store.subscribe () для прослушивания изменений в состоянии и использую его для обновления моего локального состояния.

Ниже приведен весь мой код в index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';

var store = createStore(changeState);
var initialState = {
    qty: 0,
    price: 0
}

function changeState(state = initialState, action) {
    switch (action.type) {
        case 'INCREMENT':
            var stateCopy1 = Object.assign({}, state);
            stateCopy1.qty = stateCopy1.qty + action.qty;
            stateCopy1.price = stateCopy1.price + action.price;
            return stateCopy1;
        default:
            return state;

    }
}

class Home extends React.Component {
    render() {
        return (
            <React.Fragment>
                <Comp1 /><br />
                <Comp2 />
            </React.Fragment>
        )
    }
}
class Comp1 extends React.Component {
    increase = () => {
        var action = {
            type: 'INCREMENT',
            qty: 1,
            price: 100
        }
        store.dispatch(action);
    }


    render() {
        return (
            <button type="button" onClick={this.increase}>Increase</button>
        )
    }

}
class Comp2 extends React.Component {
    constructor() {
        super();
        this.state = {
            cartQty: 0,
            cartPrice: 0
        }
    }
    render() {
        store.subscribe(() => {
            var globalState = store.getState();
            this.setState({cartQty:globalState.qty,cartPrice:globalState.price});
        })
        return (
            <div>
                <h1>Total items in cart: {this.state.cartQty}</h1>
                <h1>Total price of cart :{this.state.cartPrice}</h1>
            </div>
        )
    }
}

ReactDOM.render(<Home />, document.getElementById('root'));

Я хочу использовать response-redux, чтобы избежать локального состояния и подписки.Я читал о connect () и mapStateToProps () и.Но я не могу понять, как использовать их в моем коде ниже.Как я могу реализовать эти части в моем коде?

Ответы [ 6 ]

4 голосов
/ 29 марта 2019

Конечно, вы можете, во-первых, давайте удостоверимся, что концепции понятны.

Redux уже имеет «состояние», поэтому копирование его во внутреннее состояние является избыточным.

connect():
Этот удобный метод используется для сопоставления состояния избыточности с подпорками в вашем компоненте. То есть вы не копируете состояние в другое состояние, вы используете состояние Redux в качестве реквизита, которое является неизменным и больше похоже на ссылку на реальные данные внутри Redux.
Он построен по шаблонному вызову hoc , но это урок для другого вопроса. Важная вещь, которую нужно знать о hoc, заключается в том, что он принимает компонент в качестве аргумента и возвращает новый компонент, улучшенный.

mapStateToProps():
Это будет вашим способом сообщить connect какую часть состояния избыточности вы хотите получить внутри своего компонента. Это метод, который получает полное состояние избыточности, извлекает свойства, которые вы хотите использовать, и возвращает их для отправки в качестве реквизитов в ваш компонент.

Теперь вы упускаете одну ключевую часть эквалайзера, а именно редукса ...
Provider
Эта часть должна обернуть все ваше приложение (или ту его часть, к которой вы хотите, чтобы он имел доступ с избыточным доступом, который обычно является всем этим), и именно оно отвечает за отправку хранилища избыточного кода по дереву, чтобы connect мог его захватить. позже (это достигается через context реакции , но это еда для другой даты).
Вы получаете своего провайдера, как: import {Provider} from 'react-redux';, а затем вы даете ему магазин в качестве опоры, называемой .... store (умный, верно?)

Достаточно чата, ладно, приступим к делу.

Начнем с импорта, давайте получим все, что нам нужно:

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import {Provider, connect} from 'react-redux';

Мы добавили еще две вещи: компонент Provider и connect hoc.

var initialState = {
    qty: 0,
    price: 0
}

function changeState(state = initialState, action) {
    switch (action.type) {
        case 'INCREMENT':
            var stateCopy1 = Object.assign({}, state);
            stateCopy1.qty = stateCopy1.qty + action.qty;
            stateCopy1.price = stateCopy1.price + action.price;
            return stateCopy1;
        default:
            return state;

    }
}
var store = createStore(changeState);

Теперь, вы видели, что там произошло? Именно так! Ничего такого. Ваш редуктор может оставаться как есть, мы не двигаемся, хотя для более крупного приложения вы можете научиться комбинировать редукторы

class Home extends React.Component {
    render() {
        return (
            <Provider store={store}>
                <Comp1 /><br />
                <Comp2 />
            </Provider>
        )
    }
}

Хорошо, ваш Fragment исчез, я сожалею об этом, но теперь он больше не нужен. Fragment s используются для возврата двух или более компонентов, но поскольку Provider теперь оборачивает компоненты, нет необходимости использовать Fragment.
А что касается Provider, вам просто нужно поместить его вне всего и дать ему store. Достаточно просто.

class Comp1 extends React.Component {
    increase = () => {
        var action = {
            type: 'INCREMENT',
            qty: 1,
            price: 100
        }
        store.dispatch(action);
    }


    render() {
        return (
            <button type="button" onClick={this.increase}>Increase</button>
        )
    }

}

В этом последнем компоненте мы ничего не двигали. Хотя мы должны были, посмотрите, как вы используете store напрямую для dispatch вашего action. В обычном приложении этот компонент был бы в другом файле, поэтому у вас не было бы доступа к свойству store. И вот снова приходит наш друг connect, который помогает нам отправлять действия через функцию под названием mapDispatchToProps, о которой вы читаете здесь , но это также для другого дня.

А вот и все, чего мы все ждали, метод connect:

class Comp2 extends React.Component {

    render() {

        return (
            <div>
                <h1>Total items in cart: {this.props.qty}</h1>
                <h1>Total price of cart :{this.props.price}</h1>
            </div>
        )
    }
}

function mapStateToProps( state ){
    return { qty: state.qty, price:state.price }
}

Comp2 = connect(mapStateToProps)(Comp2);

Это может немного сбивать с толку, поэтому позвольте мне объяснить:
Сначала мы удалили все, что связано с состоянием вашего компонента. Мы больше не используем его, потому что это то, что вы хотели, верно? А также компонент теперь стал меньше. И круче.
Но что случилось позже? ну, во-первых, мы определяем функцию mapStateToProps. И это переводит состояние избыточности в состояние ваших компонентов. На этот раз мы отправляем каждое свойство из состояния избыточности в ваш компонент, но в более крупном приложении этого не произойдет, в более крупном приложении избыточность будет иметь состояние всего внутри, это могут быть элементы корзины, тема приложения. цвета, информация о пользователе и т. д. Многое, поэтому внутри этой функции мы выбираем только те свойства, которые нам интересны, чтобы попасть внутрь нашего компонента.
Теперь вызов connect ... мы переопределяем наш компонент, и это немного странно, но я попытаюсь объяснить.
connect получил наш метод mapStateToProps, а затем наш компонент. И они спарились внутри connect и дали начало другому компоненту, этот компонент будет иметь компонент, который мы сначала определили как дочерний, и всегда будет отправлять ему части состояния избыточности, которые мы просили, как реквизиты.

3 голосов
/ 29 марта 2019

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

Сначала , вам нужно установить реактив-редукс, а затем использовать компонент поставщика на верхнем уровне, на который вы передаете хранилище

Второй : Вам необходимо подключить компоненты, которым требуется доступ store или dispatch

Третий : Необходимо отобразить подключенные компоненты

Четвертый : вам необходимо mapStateToProps передать контейнеру, который имеет доступ к состоянию, и mapDispatchToProps, чтобы получить доступ к диспетчеризации или сделать создателей действий доступными в качестве реквизитов для компонентов.Если вы не передаете mapDispatchToProps в connect, по умолчанию dispatch prop предоставляется компоненту.Вы можете посмотреть API документы здесь

Пятый Создать хранилище после определения редуктора changeState и initialState

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { connect, Provider } from 'react-redux'

var initialState = {
    qty: 0,
    price: 0
}

function changeState(state = initialState, action) {
    switch (action.type) {
        case 'INCREMENT':
            var stateCopy1 = Object.assign({}, state);
            stateCopy1.qty = stateCopy1.qty + action.qty;
            stateCopy1.price = stateCopy1.price + action.price;
            return stateCopy1;
        default:
            return state;

    }
}

var store = createStore(changeState);

class Comp1 extends React.Component {
    increase = () => {
        var action = {
            type: 'INCREMENT',
            qty: 1,
            price: 100
        }
        this.props.dispatch(action);
    }


    render() {
        return (
            <button type="button" onClick={this.increase}>Increase</button>
        )
    }

}
const Comp1Container = connect()(Comp1);

class Comp2 extends React.Component {
    render() {

        return (
            <div>
                <h1>Total items in cart: {this.props.cartQty}</h1>
                <h1>Total price of cart :{this.props.cartPrice}</h1>
            </div>
        )
    }
}

const mapStateToProps = (state) => {
   return  {
      cartQty:state.qty,
      cartPrice: state.price
   }
}
const Comp2Container = connect(mapStateToProps)(Comp2);


class Home extends React.Component {
    render() {
        return (
            <React.Fragment>
                <Comp1Container /><br />
                <Comp2Container />
            </React.Fragment>
        )
    }
}
ReactDOM.render(<Provider store={store}><Home /></Provider>, document.getElementById('root'));

Рабочая демонстрация

0 голосов
/ 31 марта 2019

Во-первых, вы хотите разработать проект, который будет более модульным по мере продвижения по кривой обучения, вам будет легче.

Итак, настройте src/index.js, у вас уже есть файл index.js. Я говорю, сделайте его корневым index.js, а затем выполните рефакторинг следующим образом:

import React from "react";
import ReactDOM from "react-dom";
import "./index.scss";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";

import App from "./components/App";
import reducers from "./reducers";

const store = createStore(reducers, applyMiddleware(thunk));

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.querySelector("#root")
);

Таким образом, Provider находится на вершине иерархии и, реализовав Provider, вы сможете использовать функцию connect(), в противном случае вы получите ошибку.

Прежде чем мы перейдем к реализации connect(), давайте перейдем к иерархии, иерархия очень важная в React-Redux.

Поставщик-> Приложение -> дочерние компоненты.

Итак, следующий шаг - components/App.js:

import React from "react";
import "./App.scss";
import Home from "./Home";

const App = () => {
  return (
    <div className="App">
      <Home />
    </div>
  );
};

export default App;

Итак, давайте предположим, что вы хотите подключить connect() к вашему Home компоненту, я не думаю, что вы указали, но это будет выглядеть так:

import React from "react";
import { connect } from "react-redux";
import { fetchLocations } from "../actions";

class Home extends React.Component {
  componentDidMount() {
    this.props.fetchLocations();
  }

  render() {
    return <div>Home List</div>;
  }
}

export default connect(
  null,
  { fetchLocations }
)(Home);

Вы не много говорили о создателе ваших действий или о ваших данных о ваших данных, поэтому я просто собираюсь составить список Домов, поскольку у вас есть компонент Home. Итак, выше я импортировал функцию connect() внутри компонента, а затем я реализую ее. Обратите внимание на тот факт, что я поместил null там, где в конечном итоге окажется ваш mapStateToProps. Опять же, вы не вдавались в подробности о своем состоянии, поэтому, если я настраивал это для вас, null достаточно, чтобы ваше приложение работало, пока вы не будете готовы к реализации mapStateToProps, но действия, которые вам нужны, поэтому я создал это fetchLocations действие и реализовано внутри connect().

Для ваших редукторов вы можете сделать reducers/locationsReducer.js:

export default () => {
  return 123;
};

А затем реализовать его с вашим комбинированным редуктором, вот так: reducers/index.js:

import { combineReducers } from "redux";
import locationsReducer from "./locationsReducer";

export default combineReducers({
  locations: locationsReducer
});

Полагаю, у вас теперь есть работающее приложение React-Redux, и вы сможете его оттуда убрать.

0 голосов
/ 29 марта 2019

Код

import {combineReducers, createStore} from 'redux';
import {Provider, connect} from 'react-redux'; 
//reducer
var initialState = {
    qty: 0,
    price: 0
}

function cart(state = initialState, action) {
    switch (action.type) {
        case 'INCREMENT':
            var stateCopy1 = Object.assign({}, state);
            stateCopy1.qty = stateCopy1.qty + action.qty;
            stateCopy1.price = stateCopy1.price + action.price;
            return stateCopy1;
        default:
            return state;

    }
}

const rootReducer = combineReducers({cart});

//Actions
const increase = () => {
        var action = {
            type: 'INCREMENT',
            qty: 1,
            price: 100
        }
    }

let Comp1 = (props) => {
    return (
        <button type="button" onClick={props.increase}>Increase</button>
    )
}
Comp1 = connect(null, {increment})(Comp1);

let Comp2 = (props) => {
        return (
            <div>
                <h1>Total items in cart: {props.qty}</h1>
                <h1>Total price of cart :{props.price}</h1>
            </div>
        )
    }
const mapStateToProps = ({state}) => state.cart
Comp2 = connect(mapStateToProps)(Comp2);

//create store
const store = createStore(rootReducer);

class Home extends React.Component {
    render() {
        return (
            <Provider store={store}>
                <Comp1 /><br />
                <Comp2 />
            </Provider >
        )
    }
}

ReactDOM.render(<Home />, document.getElementById('root'));

Существует теоретическая справка о том, как использовать редукс и реагировать на ваш пример. Это должно дать вам представление о том, как использовать и то, и с небольшой помощью Google вы можете закончить свой пример, я думаю.

0 голосов
/ 29 марта 2019

Ниже приведено то, что вам нужно сделать, я привел пример с comp1 Component, также проверьте эту ссылку https://redux.js.org/basics/usage-with-react помогает получить дополнительную информацию.

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { connect } from 'react-redux'

class Comp1 extends React.Component {
    increase = () => {
        var action = {
            type: 'INCREMENT',
            qty: 1,
            price: 100
        }
        store.dispatch(action);
    }


    render() {
        return (
            <button type="button" onClick={this.increase}>Increase</button>
        )
    }
}

mapStateToProps = state =>{
  //code to map State to props
}

mapDispatchToProps = dispatch =>{
  //code to map dispatch to props
}

export deafult connect(mapStateToProps,mapDispatchToProps)(Comp1);
0 голосов
/ 29 марта 2019

используйте Provider от activ-redux, и ваш магазин будет доступен для всех ваших дочерних компонентов

                var store = createStore(changeState)
                <Provider store={store}>
                   {child}
                </Provider>
...