我正在学习redux,并编写了一个简单的代码,该代码使用store,action和reducer。我正在使用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()和。但是我无法在下面的代码中弄清楚如何使用它们。如何在代码中实现这些部分?
答案 0 :(得分:4)
当然可以,首先让我们确保概念清楚。
Redux已经具有“状态”,因此将其复制到内部状态是多余的。
connect()
:
此便捷方法用于将redux的状态映射到组件中的props。也就是说,您没有将状态复制到另一个状态,而是将Redux的状态用作props,它们是不可变的,更像是对Redux内部真实数据的引用。
它是通过模式调用hoc构建的,但这是另一个问题的教训。了解hoc的重要一点是,它将一个组件作为参数,并返回一个新的组件,即改进的组件。
mapStateToProps()
:
这将是告诉connect
您想要进入组件内部redux状态的哪一部分的方法。这种方法可以接收完整的redux状态,提取要使用的属性,然后将其作为props返回到组件。
现在,您缺少这里的关键部分,那就是redux的...
Provider
:
这部分应该包装您所有的应用程序(或您希望其具有Redux访问权的部分,通常是全部),并且是负责将Redux存储发送到树上的一个程序,因此connect
可以稍后再抓取(这是通过react的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
专案中又添加了两点。
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
用于返回两个或多个组件,但是由于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
又来了,它帮助我们通过名为here的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
函数。这会将redux的状态转换为您的组件状态。这次,我们将每个属性从redux的状态发送到您的组件,但是在更大的应用程序中情况并非如此,在更大的应用程序中,redux拥有内部所有内容的状态,这可能是购物车项目,应用程序主题颜色,用户的信息等。很多事情,因此在此函数内,我们仅选择对组件内部感兴趣的属性。
现在连接调用...我们正在重新定义我们的组件,这有点奇怪,但是我会尽力解释。
connect
收到了我们的mapStateToProps
方法,然后收到了我们的组件。然后他们在connect
内配对并生出了另一个组件,这个组件将拥有我们首先定义为孩子的组件,并且始终将其作为道具请求的redux状态的一部分发送给它。
答案 1 :(得分:3)
您需要照顾的事情很少。
首先,您需要安装react-redux,然后在将存储传递到的顶层使用Provider组件
第二:您需要连接需要访问store
或dispatch
第三:您需要渲染连接的组件
第四:您需要将mapStateToProps
传递到访问状态的容器,并需要mapDispatchToProps
来访问调度或使动作创建者可作为组件的道具使用。如果您没有将mapDispatchToProps
传递给connect
,则默认情况下dispatch
支持可用于组件。您可以查看 API docs here
第五在定义changeState reducer和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'));
答案 2 :(得分:0)
react-redux中的使用提供程序,您的商店将可用于所有子组件
var store = createStore(changeState)
<Provider store={store}>
{child}
</Provider>
答案 3 :(得分:0)
下面是您需要做的,我举了一个 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);
答案 4 :(得分:0)
代码
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的理论参考。这应该让您了解如何使用两者,并且在Google的帮助下,您可以完成我的示例。
答案 5 :(得分:0)
首先,您希望开发一个在学习过程中更加模块化的项目,对您来说会更容易。
因此,设置一个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中非常重要。
Provider-> App->子组件。
接下来是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应用程序,您应该可以从那里拿走它。