从 Reducer 到容器的 Redux 数据流
Redux Dataflow from Reducer to Container
由于我是 redux 的新手,这里有一个关于 redux 中数据流的关键问题
据我了解,我创建了一个组件作为 CountN:
import React from 'react'
import styles from '../../features/counter/Counter.module.css'
const CountN = (props) => {
const {countValue,actions} = props;
return (
<div>
<div className={styles.row}>
<button
className={styles.button}
aria-label="Increment value"
onClick={actions.increment}
>
+
</button>
<span className={styles.value}>{ countValue }</span>
<button
className={styles.button}
aria-label="Decrement value"
onClick={actions.decrement}
>
-
</button>
</div>
</div>
)
}
export default CountN
然后我用容器传数据给CountN
以下容器:
import React from 'react';
import CountN from "../../components/countN"
import { connect } from 'react-redux'
import * as CountActions from '../../actions'
import { bindActionCreators } from 'redux';
const mapStateToProps = (state) =>({
countValue: state.value
})
const mapDispatchToProps = (dispatch) =>({
actions: bindActionCreators(CountActions,dispatch)
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(CountN)
为了管理状态,我创建了 Reducer 来设置状态:
减速机如下:
import * as types from '../constants/CountTypes';
const initialState = [{
value: 0,
payload: 0,
}]
const counter = (state=initialState,action)=> {
switch (action.type){
case types.Increment:
return [{
value: state.value + 1,
payload: 0,
}]
case types.Decrement:
return [
...state,
{
value: state.value - 1
}
]
case types.IncrementByAmount:
return [{
value: state.value + action.payload ,
payload: action.payload
}
]
default:
return state
}
};
export default counter;
另外,我用“CreateStore(reducer)”创建了一个存储来存储数据,
现在问题是我得到一个错误:
类型错误:无法读取未定义的 属性 'increment'
据我了解,状态未定义,
哪位高手能帮我看看哪里错了,为什么数据没有通过“props”传递给Container???
非常感谢
你的代码应该可以工作,但我确实对状态做了一些更改,你将它定义为一个数组,但我没有看到为什么所以我将它更改为一个对象。您的 mapStateToProps 不认为状态是一个数组,所以这可能是一个错误。请参阅下面我进行更改的代码中的注释。
const { Provider, connect } = ReactRedux;
const {
createStore,
applyMiddleware,
compose,
bindActionCreators,
} = Redux;
//I changed initialState to an object instead of an array
const initialState = {
value: 0,
payload: 0,
};
//action types
const types = {
Increment: 'Increment',
Decrement: 'Decrement',
IncrementByAmount: 'IncrementByAmount',
};
//action creators
const CountActions = {
increment: () => ({ type: types.Increment }),
decrement: () => ({ type: types.Decrement }),
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case types.Increment:
//changed to object
return {
value: state.value + 1,
payload: 0,
};
case types.Decrement:
//changed to object
return {
...state,
value: state.value - 1,
};
case types.IncrementByAmount:
//changed to object
return {
value: state.value + action.payload,
payload: action.payload,
};
default:
return state;
}
};
//creating store with redux dev tools
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducer,
initialState,
composeEnhancers(
applyMiddleware(() => (next) => (action) =>
next(action)
)
)
);
const CountN = (props) => {
const { countValue, actions } = props;
return (
<div>
<div>
<button
aria-label="Increment value"
onClick={actions.increment}
>
+
</button>
<span>{countValue}</span>
<button
aria-label="Decrement value"
onClick={actions.decrement}
>
-
</button>
</div>
</div>
);
};
const mapStateToProps = (state) => ({
countValue: state.value,
});
const mapDispatchToProps = (dispatch) => ({
actions: bindActionCreators(CountActions, dispatch),
});
const App = connect(
mapStateToProps,
mapDispatchToProps
)(CountN);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<div id="root"></div>
由于我是 redux 的新手,这里有一个关于 redux 中数据流的关键问题
据我了解,我创建了一个组件作为 CountN:
import React from 'react'
import styles from '../../features/counter/Counter.module.css'
const CountN = (props) => {
const {countValue,actions} = props;
return (
<div>
<div className={styles.row}>
<button
className={styles.button}
aria-label="Increment value"
onClick={actions.increment}
>
+
</button>
<span className={styles.value}>{ countValue }</span>
<button
className={styles.button}
aria-label="Decrement value"
onClick={actions.decrement}
>
-
</button>
</div>
</div>
)
}
export default CountN
然后我用容器传数据给CountN
以下容器:
import React from 'react';
import CountN from "../../components/countN"
import { connect } from 'react-redux'
import * as CountActions from '../../actions'
import { bindActionCreators } from 'redux';
const mapStateToProps = (state) =>({
countValue: state.value
})
const mapDispatchToProps = (dispatch) =>({
actions: bindActionCreators(CountActions,dispatch)
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(CountN)
为了管理状态,我创建了 Reducer 来设置状态:
减速机如下:
import * as types from '../constants/CountTypes';
const initialState = [{
value: 0,
payload: 0,
}]
const counter = (state=initialState,action)=> {
switch (action.type){
case types.Increment:
return [{
value: state.value + 1,
payload: 0,
}]
case types.Decrement:
return [
...state,
{
value: state.value - 1
}
]
case types.IncrementByAmount:
return [{
value: state.value + action.payload ,
payload: action.payload
}
]
default:
return state
}
};
export default counter;
另外,我用“CreateStore(reducer)”创建了一个存储来存储数据,
现在问题是我得到一个错误:
类型错误:无法读取未定义的 属性 'increment'
据我了解,状态未定义,
哪位高手能帮我看看哪里错了,为什么数据没有通过“props”传递给Container???
非常感谢
你的代码应该可以工作,但我确实对状态做了一些更改,你将它定义为一个数组,但我没有看到为什么所以我将它更改为一个对象。您的 mapStateToProps 不认为状态是一个数组,所以这可能是一个错误。请参阅下面我进行更改的代码中的注释。
const { Provider, connect } = ReactRedux;
const {
createStore,
applyMiddleware,
compose,
bindActionCreators,
} = Redux;
//I changed initialState to an object instead of an array
const initialState = {
value: 0,
payload: 0,
};
//action types
const types = {
Increment: 'Increment',
Decrement: 'Decrement',
IncrementByAmount: 'IncrementByAmount',
};
//action creators
const CountActions = {
increment: () => ({ type: types.Increment }),
decrement: () => ({ type: types.Decrement }),
};
const reducer = (state = initialState, action) => {
switch (action.type) {
case types.Increment:
//changed to object
return {
value: state.value + 1,
payload: 0,
};
case types.Decrement:
//changed to object
return {
...state,
value: state.value - 1,
};
case types.IncrementByAmount:
//changed to object
return {
value: state.value + action.payload,
payload: action.payload,
};
default:
return state;
}
};
//creating store with redux dev tools
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducer,
initialState,
composeEnhancers(
applyMiddleware(() => (next) => (action) =>
next(action)
)
)
);
const CountN = (props) => {
const { countValue, actions } = props;
return (
<div>
<div>
<button
aria-label="Increment value"
onClick={actions.increment}
>
+
</button>
<span>{countValue}</span>
<button
aria-label="Decrement value"
onClick={actions.decrement}
>
-
</button>
</div>
</div>
);
};
const mapStateToProps = (state) => ({
countValue: state.value,
});
const mapDispatchToProps = (dispatch) => ({
actions: bindActionCreators(CountActions, dispatch),
});
const App = connect(
mapStateToProps,
mapDispatchToProps
)(CountN);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.5/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/7.2.0/react-redux.min.js"></script>
<div id="root"></div>