reactjs 如何使用React-redux来避免代码中的局部状态?

p4tfgftt  于 2023-06-05  发布在  React
关注(0)|答案(6)|浏览(134)

我正在学习redux,我已经提出了一个简单的代码,其中使用的商店,行动和减少。我使用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'));

我想使用react-redux来避免本地状态和订阅。我读到了connect()和mapStateToProps()。但是我不知道如何在下面的代码中使用它们。如何在代码中实现这些部分?

rvpgvaaj

rvpgvaaj1#

当然可以,首先让我们确保概念清晰。
Redux已经有了一个“状态”,所以将它复制到内部状态是多余的。
connect()
这个方便的方法用于将redux的状态Map到组件中的props。也就是说,你并没有将状态复制到另一个状态中,你使用Redux的状态作为props,它是不可变的,更像是对Redux内部真实的数据的引用。
它是用模式调用hoc构建的,但这是另一个问题的教训。关于hoc,需要知道的重要一点是,它接受一个组件作为参数,并返回一个新的组件,一个改进的组件。
mapStateToProps()
这将是您告诉connect您希望在组件中获取redux状态的哪一部分的方式。它是一个接收完整redux状态的方法,提取您想要使用的属性,并返回它们以作为props发送到您的组件。
现在你错过了一个关键的部分,这是redux的...
Provider
这部分应该包含你的应用的全部(或者你希望它拥有redux访问权限的部分,通常是全部),并且负责将redux的商店发送到树下,以便connect稍后可以获取它(这是通过react的context实现的,但这是另一个日期的晚餐)。
你得到你的供应商像:import {Provider} from 'react-redux';然后你给予它商店作为一个 prop 叫做.... 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);

现在,你看到发生了什么?没错没什么。您的reducer可以保持原样,我们不会移动它,尽管对于较大的应用程序,您可能需要学习combine reducers

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

好吧,你的Fragment不见了,我很抱歉,但它现在不再需要了。Fragment s用于返回两个或多个组件,但由于Provider现在 Package 组件,因此不需要使用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直接用于dispatchaction的。在一个普通的应用程序中,这个组件会在另一个文件中,所以你不能访问store属性。我们的朋友connect又来了,它帮助我们通过一个叫做mapDispatchToProps的函数来调度操作,你读过here,但这也是另一天的事情。
我们都在等待的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函数。这是将redux的状态转换为组件的状态。这一次,我们将redux的状态中的每个属性发送到您的组件,但在更大的应用程序中,情况并非如此,在更大的应用程序中,redux将包含所有内容的状态,可能是购物车项目,应用程序主题颜色,用户信息等。很多东西,所以在这个函数中,我们只选择我们感兴趣的属性。
现在接通电话...我们正在重新定义我们的组件,这有点奇怪,但我会试着解释。
connect接收了我们的mapStateToProps方法,然后是我们的组件。它们在connect内部交配并产生了另一个组件,这个组件将拥有我们首先定义为子组件的组件,并且总是将我们要求的redux状态部分作为 prop 发送给它。

pwuypxnk

pwuypxnk2#

有几件事你需要照顾。

首先,需要安装react-redux,然后在顶层使用Provider组件,将store传递给它
第二步:连接需要访问storedispatch的组件
第三:需要渲染连接的组件
第四:需要mapStateToProps传递给访问状态的容器,mapDispatchToProps传递给访问调度的容器,或者让action creator作为props提供给组件。如果您没有将mapDispatchToProps传递给connect,则默认情况下,dispatch属性对组件可用。您可以查看**API docs here**
第五定义changeState reducer和initialState后创建store

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'));

Working demo

hsvhsicv

hsvhsicv3#

使用react-redux中的Provider,您的商店将可用于所有子组件

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

svmlkihl4#

下面是你需要做的,我已经给出了一个comp1组件的例子,也检查这个链接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);
uurv41yg

uurv41yg5#

代码

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'));

这里有一个基于你的例子的如何使用redux和react-redux的理论参考。这应该给予你的想法如何使用这两个和小谷歌的帮助,你可以完成你的例子,我猜。

swvgeqrz

swvgeqrz6#

首先,你想开发一个更加模块化的项目,随着你的学习曲线沿着,这对你来说会更容易。
所以设置一个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;
};

然后用你的组合reducer实现它,像这样,reducers/index.js

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

export default combineReducers({
  locations: locationsReducer
});

我相信你现在已经有了一个正常运行的React-Redux应用程序,你应该能够从那里拿走它。

相关问题