我很难理解应该如何使用反应组件的操作调度全局存储。我对整个概念都很陌生,我不会让我的组件在dispatch()上重新渲染。我投入了很多,发现虽然reducer返回更新的全局状态,但值不会映射回组件props。但是定义了一个合适的函数(mapStateToProps)。
最小示例:pundit(或下面的最小示例代码)。
说明:
我有一个组件Controls
,其方法为switchActivities
。组件连接到全局存储,我的全局状态在组件props中可用。
var PullFromStoreControls = function (state) {
return {
concrete: state.me.bool,
nested: state.me.nested.later
}
}
var PushToStoreControls = function (dispatch) {
return {
switchFilter: function (type, value) {
dispatch({
type: 'SET_VAL',
value: value
})
}
}
}
Controls = connect(
PullFromStoreControls,
PushToStoreControls
)(Controls)
我将变量state.me.bool
连接到 props.conrete 以避免深度状态树的副作用。我还连接了一个调度程序,通过reducer更新全局状态。但是,如果调度员是由“交换活动”调用的,那么复选框的新值使其正确到达reducer,然后丢失。全局状态似乎永远不会正确更新。
我错过了什么?
<!DOCTYPE html>
<html>
<head>
<script data-require="react@*" data-semver="15.5.0" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.0/react.min.js"></script>
<script data-require="react@*" data-semver="15.5.0" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.0/react-dom.min.js"></script>
<script data-require="redux@*" data-semver="3.2.1" src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.2.1/redux.js"></script>
<script data-require="react-redux@*" data-semver="4.4.5" src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/4.4.5/react-redux.js"></script>
<!-- support for jsx on my localhost, on Plunkr jsx will be automatically transpiled to js -->
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type = "text/babel" src="minimal.jsx"></script>
</head>
<body>
<div id="app"></div>
</body>
</html>
function d(x){
console.log(x);
}
const AppState = {
me: {
bool: false,
nested: {
later: "I also want to change values deeper in the tree."
}
}
}
function reducer(state, action) {
if (state === undefined) {
return AppState;
}
switch (action.type) {
case 'SET_VAL':
state.me.bool = action.value;
break;
}
console.log("The reducer returns the changed state");
console.log(state);
return state;
}
// create global store with initial configuration `AppState`
const store = Redux.createStore(reducer, AppState);
// create provider and connect function not having webpack available
var Provider = ReactRedux.Provider;
var connect = ReactRedux.connect;
class Controls extends React.Component {
switchActivities() {
console.log("------------------ clicked ------------------");
console.log("set value from:");
console.log(this.props.concrete);
// inverse current state
const state = !this.props.concrete;
// output
console.log("to:");
console.log(state);
// call dispatcher
this.props.switchFilter("show_act", state);
}
render() {
console.log("I would like to re-render if this.props.concrete has updated!");
const switchActivities = <MapSwitch name="switch_act" label="Show something" checked={this.props.concrete} onChange = {() => this.switchActivities()} />;
return <div id="map-controls">
{switchActivities}
</div>
}
}
var PullFromStoreControls = function (state) {
return {
concrete: state.me.bool,
nested: state.me.nested.later
}
}
var PushToStoreControls = function (dispatch) {
return {
switchFilter: function (type, value) {
dispatch({
type: 'SET_VAL',
value: value
})
}
}
}
Controls = connect(PullFromStoreControls, PushToStoreControls)(Controls)
const MapSwitch = ({name, label, checked, onChange}) => (
<label for={name}>{label}
<input type="checkbox" className="switch" data-toggle="switch"
name={name}
onChange={onChange}
checked={checked}
/>
</label>
)
ReactDOM.render(
<Provider store={store}>
<Controls/>
</Provider>,
document.getElementById('app')
);
是是否有区别我是否更改了reducer中的state
对象并返回该对象,或者我是否创建了一个新对象并返回该对象。虽然两个返回的对象都是相同的,但前者是引用,而后者是一个真正的新变量。我学到了很难的方法。
好的解释: Please have a look at this plunkr
function reducer(state, action) {
switch (action.type) {
case 'SET_VAL':
return {
...state,
me : {
...state.me,
bool: action.value
}
}
}
return state;
}
答案 0 :(得分:1)
您的问题是您正在改变state
。 Redux的第二个原则是state
永远不应该直接变异 - 相反,你的reducer是一个纯函数,它应该return
一个新状态:https://redux.js.org/docs/introduction/ThreePrinciples.html#changes-are-made-with-pure-functions
您的问题在这里:
switch (action.type) {
case 'SET_VAL':
// you are attempting to mutate state.me.bool - this is an antipattern!
state.me.bool = action.value;
break;
}
相反,请以返回state
。
function reducer(state, action) {
switch (action.type) {
case 'SET_VAL':
return {
...state,
me : {
...state.me,
bool: action.value
}
};
default:
return state;
}
}
请注意,您需要为嵌套结构复制state
的每个级别。我在这里使用Object spread操作符,但Object.assign()使用了所有工作。希望这有帮助!