new user to Redux so apologies for any silly mistakes. Ultimately, I am trying to toggle a className in component B as an onClick function toggles a state in component A.
So it should be: Component A button click => state toggles => Component B className toggles.
I have setup my store and my mapDispatchToProps function that changes the state in my store seems to be working. However, calling this state in a different component is working... but, does not re-render as the state in the store toggles. There is more content in my code, but I've tried to strip the parts that are not necessary to this issue.
Component A - containing a button that toggles a state and changes a state within my store/rootReducer:
import React from 'react';
import { connect } from 'react-redux';
function Nav(props) {
const [showMenu, setShowMenu] = React.useState('menuClosed');
function menuClick() {
showMenu === 'menuClosed' ? setShowMenu('menuOpen') :
setShowMenu('menuClosed');
}
// this works fine, I know this due to the console.log on my rootReducer page:
React.useEffect(() => {
props.toggleMenu(showMenu);
}, [showMenu])
return (
<button className="hvr-icon-grow-rotate" id="bars" onClick={() => { menuClick(); }}>
<FontAwesomeIcon icon={faBars} className="hvr-icon" />
</button>
)
}
const mapStateToProps = (state) => {
return {
menu: state.menu
}
}
const mapDispatchToProps = (dispatch) => {
return {
toggleMenu: (showMenu) => {
dispatch({ type: 'TOGGLE_MENU', menu: showMenu })
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Nav)
Component B: supposed to toggle a className depending on store state:
import React from 'react';
import { connect } from 'react-redux';
const [noHover, setNoHover] = React.useState('projectGrid');
React.useEffect(() => {
console.log('portfolio props: ' + props.menu + ' noHover: ' + noHover);
if (props.menu === 'menuOpen') {
setNoHover('projectGrid noHover');
console.log('portfolio props: ' + props.menu + ' noHover: ' + noHover);
}
else if (props.menu === 'menuClosed') {
setNoHover('projectGrid');
console.log('portfolio props: ' + props.menu + ' noHover: ' + noHover);
}
}, [])
return (<div className={noHover}>some content</div>);
}
const mapStateToProps = (state) => {
return {
menu: state.menu
}
}
export default connect(mapStateToProps)(PortfolioItem)
finally, content of my rootReducer.js page, or the Redux store:
const initState = {
menu: ['menuClosed']
}
const rootReducer = (state = initState, action) => {
console.log(action);
return state;
}
export default rootReducer;
Any help would be greatly appreciated - thank you!
It doesn't look like you're actually toggling anything in your reducer.
You need to return a new state if you want it to change. I'm not sure exactly how it should look in your case, but something like this:
const rootReducer = (state = initState, action) => {
let newState = {...state}; // Create a new state object so we don't mutate original
switch(action.type) { // Check what type was sent to see if we should update
case 'TOGGLE_MENU':
newState.menu = action.menu; // Set new state based on action
return newState;
default:
return state; // Return old state if nothing changed
}
}
Side note: it looks like your initial state has menu as an array, but your components don't treat it as one. It seems like it should be defaulted to a string.
It looks like @brian-thompson has solved your problem, so I won't solve it again, but I would say you can make your styling logic a log easier by using the classnames library.
Your useEffect callback would be replaced with
const { menu } = props
const noHover = classNames({
'projectGrid': true,
'noHover': menu === 'menuOpen'
})
Removing the need for any hooks.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.