gpt4 book ai didi

javascript - ReactJs Redux : how to dispatch an action on a user event and link actions with the reducers and the store

转载 作者:行者123 更新时间:2023-11-28 06:05:31 25 4
gpt4 key购买 nike

对于reactJs和redux来说还很陌生,尽管有教程(包括redux中的todolist示例),我仍然很难理解如何实际触发将改变状态的操作。

我已经构建了一些非常简单的东西,并且加载良好。有人可以帮助我发送一个操作,最终导致商店数据被更改吗?

我希望当用户单击 li.module 时调用togglePriceModule 函数。我是否需要调用作为 props 传递给子组件的主 Pricing 组件的函数?正确的做法是什么?

非常感谢!

我的app.js:

//Importing with braces imports a specific export of the file
import { createDevTools } from 'redux-devtools'
//Importing without braces imports the default export of the file
import LogMonitor from 'redux-devtools-log-monitor'
import DockMonitor from 'redux-devtools-dock-monitor'

import React from 'react'
import ReactDOM from 'react-dom'
//Redux helps manage a single state which can be updated through actions call pure reducers
//Importing muliple items injects them into the current scope
import { applyMiddleware, compose, createStore, combineReducers } from 'redux'
import { Provider } from 'react-redux'
//React-router helps switch between components given a specific route
import { Router, Route, Link } from 'react-router'
import createHistory from 'history/lib/createHashHistory'
import { syncHistory, routeReducer } from 'react-router-redux'

//Imports an object of elements correspondings to every export of the file
import * as reducers from './reducers';

import Pricing from './components/pricing/pricing_main.js';

const history = createHistory();
const middleware = syncHistory(history);
const reducer = combineReducers({
...reducers,
routing: routeReducer
});

const DevTools = createDevTools(
<DockMonitor toggleVisibilityKey="ctrl-q"
changePositionKey="ctrl-alt-q"
defaultIsVisible={false}>
<LogMonitor theme="tomorrow" preserveScrollTop={false} />
</DockMonitor>
);

const finalCreateStore = compose(
applyMiddleware(middleware),
DevTools.instrument()
)(createStore);

const store = finalCreateStore(reducer);

middleware.listenForReplays(store);

var renderComponent = function(component, id) {
var reactContainer = document.getElementById(id);
if (null !== reactContainer) {
ReactDOM.render(
<Provider store={store}>
<div>
<Router history={history}>
<Route path="/" component={component} />
</Router>
<DevTools />
</div>
</Provider>,
reactContainer
);
}
};

renderComponent(Pricing, 'react-pricing');

我的定价组成部分:

import React from 'react';
var _ = require('lodash');

const Pricing = React.createClass({
getInitialState: function(){
return {
modules: {
'cms' : {
title: 'Fiches techniques & Mercuriale',
subtitle: 'Gérez votre connaissance sous un format structuré',
price: 15,
details: [
'première ligne',
'deuxième ligne',
'troisième ligne'
],
'activated': true
},
'cycle' : {
title: 'Cycle de menus',
subtitle: 'Programmez votre production dans le temps',
price: 20,
details: [
'première ligne',
'deuxième ligne',
'troisième ligne'
],
'activated': false
},
'organigram' : {
title: 'Organigramme de production',
subtitle: "Optimisez l'affectation de votre main d'oeuvre",
price: 20,
details: [
'première ligne',
'deuxième ligne',
'troisième ligne'
],
'activated': false
},
'teams' : {
title: 'Planning des équipes',
subtitle: "Gérez les temps de présence de vos salariés",
price: 20,
details: [
'première ligne',
'deuxième ligne',
'troisième ligne'
],
'activated': false
},
'orders' : {
title: 'Commandes et stocks',
subtitle: "Commandez en un clic auprès de vos fournisseurs",
price: 20,
details: [
'première ligne',
'deuxième ligne',
'troisième ligne'
],
'activated': false
}
},
options : {
users: {
title: "Nombre d'utilisateurs",
subtitle: "Distribuez des accès sécurisés",
price: 5,
unit: "5€ par utilisateur",
type: 'quantity',
value: 1
},
sites: {
title: 'Sites de vente ou de production',
subtitle: "Gérez vos multiples sites dans la même interface",
unit: "50€ par site",
type: 'quantity',
value: 1
},
backup: {
title: 'Sauvegarde',
subtitle: "Recevez une copie Excel de vos données tous les jours",
type: 'switch',
value: 'day'
}
}
}
},
componentWillMount: function(){
this.setState(this.getInitialState());
},
render: function () {
return (
<div className="wrapper">
<h1>Paramétrez votre offre</h1>
<div id="elements">
<ul id="module-container" className="flex-container col">
{_.map(this.state.modules, function(module, key) {
return <Module key={key} data={module} />
})}
</ul>
<ul id="param_container">
{_.map(this.state.options, function(option, key) {
return <Option key={key} data={option} />
})}
</ul>
</div>
<div id="totals" className="flex-container sp-bt">
<span>Total</span>
<span>{calculatePrice(this.state)}</span>
</div>
</div>
);
}
});

function calculatePrice(state) {
var modulePrices = _.map(state.modules, function(item){
return item.price;
});
modulePrices = _.sum(modulePrices);

return modulePrices;
}

var Module = React.createClass({
render: function(){
var data = this.props.data;
return <li className="module">
<div className="selection">
<i className={data.activated ? 'fa fa-check-square-o' : 'fa fa-square-o'} />
</div>
<div className="title">
<h3>{data.title}</h3>
<h4>{data.subtitle}</h4>
</div>
<div className="price">
<div className="figure">{data.price}</div>
<div className="period">par mois</div>
</div>
<ul className="details">{
data.details.map(function(item, key){
return <li key={key}><i className="fa fa-check" />{item}</li>
})}
</ul>
</li>
}
});

var Option = React.createClass({
render: function(){
var data = this.props.data;
return <li className="param">
<div className="title">
<h3>{data.title}</h3>
<h4>{data.subtitle}</h4>
</div>
<div className="config">
<span className="figure"><i className="fa fa-minus" /></span>
<input value="1"/>
<span className="plus"><i className="fa fa-plus" /></span>
</div>
</li>
}
});

export default Pricing;

我的行动:

import { TOGGLE_PRICE_MODULE, INCREASE_PRICE_OPTION, DECREASE_PRICE_OPTION } from '../constants/constants.js'

export function increasePriceOption(value) {
return {
type: INCREASE_PRICE_OPTION,
value: value
}
}

export function decreasePriceOption(value) {
return {
type: DECREASE_PRICE_OPTION,
value: value
}
}

export function togglePriceModule(activated) {
return {
type: TOGGLE_PRICE_MODULE,
activated: activated
}
}

我的 reducer :

import { TOGGLE_PRICE_MODULE, INCREASE_PRICE_OPTION, DECREASE_PRICE_OPTION } from '../constants/constants.js'


export default function updateModule(state = false, action) {
if(action.type === TOGGLE_PRICE_MODULE) {
return !state;
}
return state
}

export default function updateOption(state = 1, action) {
if(action.type === INCREASE_PRICE_OPTION) {
return state + 1;
}
else if(action.type === DECREASE_PRICE_OPTION) {
if (state < 2) {
return 1;
} else {
return state + 1;
}
}
return state

编辑 1

我已经隔离了模块组件,并尝试根据下面的第一个答案进行调整:模块正确加载,但 View 中根本没有任何效果。缺少一些东西吗?

第一个错误:我需要改变

import * as reducers from './reducers';

进入

import * as reducers from './reducers/pricing.js';

控制台日志实际显示我的 reducer 。

为什么?

第二:console.log 显示该操作确实被调用 reducer 中的情况相同表明事实并非如此。我应该如何在reducer和action之间建立链接?我应该使用 mapStateToProps 并以某种方式连接吗?

import React from 'react';
import { togglePriceModule } from '../../actions/pricing.js';

var Module = React.createClass({
handleClick: function(status){
this.context.store.dispatch(togglePriceModule(status));
},
render: function(){
console.log(this.props);
var data = this.props.data;
return <li className="module" onClick={this.handleClick}>
<div className="selection">
<i className={data.activated ? 'fa fa-check-square-o' : 'fa fa-square-o'} />
</div>
<div className="title">
<h3>{data.title}</h3>
<h4>{data.subtitle}</h4>
</div>
<div className="price">
<div className="figure">{data.price}</div>
<div className="period">par mois</div>
</div>
<ul className="details">{
data.details.map(function(item, key){
return <li key={key}><i className="fa fa-check" />{item}</li>
})}
</ul>
</li>
}
});

Module.contextTypes = {
store: React.PropTypes.object
};

export default Module;
}

编辑2

我已按照建议进行了更改,现在调用了 reducer 。但是我没有更改用户界面,所以我猜测我做错了什么。 我处理状态/商店/ Prop 的方式正确吗?

该 bundle 有效,但我在控制台中收到以下错误:

warning.js:45 Warning: setState(...): Cannot update during an existing state transition (such as within render). Render methods should be a pure function of props and state.

此外,我是否应该将函数从定价组件(容器)传递到模块组件并将逻辑放在上面,而不是在子模块组件中分派(dispatch)操作?

我更新的模块组件,我点击它希望 UI 发生变化:

import React from 'react';
import { connect } from 'react-redux';
import { togglePriceModule } from '../../actions/pricing.js';

var Module = React.createClass({
handleClick: function(status){
this.context.store.dispatch(togglePriceModule(status));
},
render: function(){
var data = this.props.data;
return <li className="module" onClick={this.handleClick(!data.activated)}>
<div className="selection">
<i className={data.activated ? 'fa fa-check-square-o' : 'fa fa-square-o'} />
</div>
<div className="title">
<h3>{data.title}</h3>
<h4>{data.subtitle}</h4>
</div>
<div className="price">
<div className="figure">{data.price}</div>
<div className="period">par mois</div>
</div>
<ul className="details">{
data.details.map(function(item, key){
return <li key={key}><i className="fa fa-check" />{item}</li>
})}
</ul>
</li>
}
});

Module.contextTypes = {
store: React.PropTypes.object
};

function mapStateToProps(state) {
return {
data: state.updateModule.data
}
}

export default connect(mapStateToProps)(Module)

export default Module;

我的行动:

export function togglePriceModule(status) {
return {
type: TOGGLE_PRICE_MODULE,
activated: status
}
}

我的 reducer :

import { TOGGLE_PRICE_MODULE, INCREASE_PRICE_OPTION, DECREASE_PRICE_OPTION } from '../constants/constants.js'

export function updateModule(state = {}, action) {
console.log('updateModule reducer called');
if(action.type === TOGGLE_PRICE_MODULE) {
return {...state, activated : action.activated };
}
return state
}

export function updateOption(state = {}, action) {
if(action.type === INCREASE_PRICE_OPTION) {
return {...state, value: state.value + 1};
} else if(action.type === DECREASE_PRICE_OPTION) {
if (state.value < 2) {
return {...state, value : 1};
} else {
return {...state, value : state.value - 1};
}
}
return state
}

最佳答案

首先dispatch是一个存储函数。您需要将商店作为引用,然后导入您的操作并调度它。 reducer 将处理逻辑并返回将触发渲染的新状态。

添加此:

Pricing.contextTypes = {
store: React.PropTypes.object
};

您应该有商店引用信息。

然后只需导入您的操作:

import myAction from './myPath'

然后通过这样做:

this.context.store.dispatch(myAction(myVar));

这将触发调度,该调度将返回新状态并触发渲染。

例如:

handleClick() {
this.context.store.dispatch(myAction());
}

和内部渲染:

<a onClick={this.handleClick}>test</a>

我在那里使用 ES6 语法。

基本上这个过程应该非常简单,除非我在你的问题中遗漏了一些东西。

或者,如果你在 console.log(this.props) 中看到调度,你可以:

  this.props.dispatch(myAction(myVar));

回答你的这两个问题:我应该如何在reducer和action之间建立联系?我应该使用 mapStateToProps 并以某种方式连接吗?

是的,您必须在组件中导入 connect 才能与商店建立链接:

import { connect } from 'react-redux';

是的,您需要将状态映射到 Prop :

function mapStateToProps(state) {
return {
myVar: state.myReducer.myVar
}
}

最后使用 connect 将所有内容包装在一起。

export default connect(mapStateToProps)(Pricing)

关于javascript - ReactJs Redux : how to dispatch an action on a user event and link actions with the reducers and the store,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36901292/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com