Reputation: 21
I'm using Redux in an application for the first time and having trouble understanding how to pass a component's internal state to the global state object.
export default class ComponentOne extends Component {
constructor() {
this.state = {
number: 0
}
handleNumber = (e) => {
this.setState({
number: e.target.value
})
}
render() {
console.log(this.state.number)
return (
<div>
<input onChange={this.handleNumber} type="number">
</div>
)
}
}
}
function mapStateToProps(state) {
return {
number: state
}
}
export default connect(mapStateToProps, { HANDLE_NUMBER_CHANGE })(ComponentOne);
My Actions & Reducers:
const HANDLE_NUMBER_CHANGE = state => {
return {
type: 'HANDLE_NUMBER_CHANGE'
}
}
export default (state = 0, action) {
switch(action.type) {
case 'HANDLE_NUMBER_CHANGE':
//Im lost here - trying to save internal state
default:
return state;
}
}
My store is set up properly, using redux-thunk for middleware.
When I log store.getState()
- it is logging 0 regardless of my components internal state.
Can anybody explain how this works?
Upvotes: 1
Views: 8459
Reputation: 15292
If you are managing your ComponentOne
state using redux then you dont need
react state.
ComponentOne
export default class ComponentOne extends Component {
constructor() {
handleNumber = (e) => {
this.props.updateNumber(e.target.value);//call dispatch method
}
render() {
return (
<div>
<input onChange={this.handleNumber} type="number">
</div>
)
}
}
}
function mapStateToProps(state) {
return {
number: state.number //map updated number here
}
}
function mapDispatchToProps(state) {
return {
updateNumber(number){
dispatch({type: 'HANDLE_NUMBER_CHANGE',number});//dispatch action
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ComponentOne);
reducers:
export default (state = 0, action) {
switch(action.type) {
case 'HANDLE_NUMBER_CHANGE':
return {
...state,number : actio.number//update number here
}
default:
return state;
}
}
Upvotes: 0
Reputation: 6027
When you have global state you dont need to save it to the local state. It is accessible to the component as this.props.value.
The way to set global state is by passing the value to the action creator, which returns it in the action. The reducer gets it in the action object and saves it.
There are many simple examples available. Here is one.
Here is your code after changes: (I didn't run it - there might be errors, but I believe that you will be able to fix them by yourself; I have divided the code between several files - this is how usually how this is done. Look in the example in the above link if you have problems)
// file: src/components/ComponentOne.js
import React from 'react';
import { connect } from 'react-redux';
import { handleNumber } from '../actions';
class ComponentOne extends Component {
constructor(props) {
super(props);
this.handleNumber = this.handleNumber.bind(this);
}
render() {
console.log(this.state.number)
return (
<div>
<input onChange={(e) => this.props.handleNumber(e.target.value)} type="number" />
</div>
);
}
}
function mapStateToProps(state) {
return {
number: state
}
}
export default connect(mapStateToProps, { handleNumber })(ComponentOne);
// end of file
/// separate file: src/reducers/index.js ////
import { combineReducers } from 'redux';
import dataReducer from './dataReducer';
export default combineReducers({
number: dataReducer
});
// end of file
// separate file: src/reducers/dataReducer.js
const DataReducer = (state = 0, action) => {
switch(action.type) {
case 'HANDLE_NUMBER_CHANGE':
return action.payload;
default:
return state;
}
};
export default DataReducer;
// end of file
// separate file: src/actions/index.js
export function handleNumber(value) {
return ({
type: 'HANDLE_NUMBER_CHANGE',
payload: value
});
}
Upvotes: 1
Reputation: 116
I don't see the logic in making your internal state equal your store. I'm not saying you're wrong, but it doesn't seem to fit within the redux paradigm. However...
Action should be...
export function HANDLE_NUMBER_CHANGE = number => {
return {
type: 'HANDLE_NUMBER_CHANGE'
payload: number
}
}
Reducer should look like...
export default (state = {number: 0}, action) {
switch(action.type) {
case 'HANDLE_NUMBER_CHANGE':
return (state = {
...state,
number: action.payload,
});
Lastly, you'll need to call a dispatch from your onChange function.
dispatch(HANDLE_NUMBER_CHANGE(e.target.value).
If you do not pass the value to the action, there is no way for the reducer to add it to the store.
Upvotes: 0