You looking for useSelector hook.
Do not use store.getState() in functional component. Also, you do not need to connect functions components, use useDispatch hook.
Getting values from store will be like this:
const todos = useSelector(store => store.items);
Answer from Anton Neverov on Stack OverflowYou looking for useSelector hook.
Do not use store.getState() in functional component. Also, you do not need to connect functions components, use useDispatch hook.
Getting values from store will be like this:
const todos = useSelector(store => store.items);
It's very odd they (code bootcamp) would require you to use a function component and then not allow you to use the React hooks that make the function components so appealing. No worries, you can still use the older connect Higher Order Component to inject your redux state and dispatchable actions into the props passed to the component.
You've an issue in AddToDo component. You are passing the mapDispatchToProps to the connect HOC where the mapStateToProps callback would be passed. You also aren't using the injected addTodo action you just mapped. You almost won't ever need to access the store object directly to dispatch actions, use the React components/hooks.
export function AddTodo() {
const [state, setState] = React.useState({
title:"",
description:"",
place:"",
date:"",
});
function handleChange(e) {
const { value } = e.target;
setState(prevState => ({ // <-- use functional state update
...prevState,
[e.target.name]:value
}));
}
function handleSubmit(e) {
e.preventDefault();
this.props.addTodo({ // <-- addTodo action injected into props
place:state.place,
title:state.title,
date:state.date,
description:state.description
});
setState({
title:"",
description:"",
place:"",
date:"",
});
}
return (
<div className="todoContainer">
...
</div>
)
};
const mapDispatchToProps = {
addTodo,
}
export default connect(null, mapDispatchToProps)(AddTodo); // <-- mapStateToProps is null
In Todos component, your todos state is an array, so you likely want to map it to JSX. Remember to destructure the passed props. Since you didn't share your reducers or how you combine your reducers I'm going to assume there is just one reducer for todos located at the state root.
[update]
Since it seems your rootReducer is just your todos reducer function and I don't see where combineReducers is used to build a more complex state tree, state IS your todos array state you are trying to pass to Todos component.
[/update]
function Todos({ todos }) {
return (
<div className="todoDetail">
{todos.map((todo) => (
<h4 key={todo.id}>{todo.title}</h4>
))}
</div>
)
};
function mapStateToProps(state) {
return {
todos: state, // <-- state is todos array
};
}
export default connect(mapStateToProps)(Todos);
Videos
As of version 7.x react-redux now has hooks for functional components.
Header.jsx
import React from 'react';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import s from './Header.css';
import { Navbar, Nav } from 'react-bootstrap';
import HeaderMenu from '../HeaderMenu';
import cx from 'classnames';
import { useSelector } from 'react-redux'
function Header() {
const store = useSelector(store => store)
return (
<Navbar fluid fixedTop id="Header" className={s.navContainer}>
<Nav block className={cx(s.HeaderTitle, s.hideOnSmall)}>Project title</Nav>
<HeaderMenu />
</Navbar>
);
}
export default withStyles(s)(Header);
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux'
import store from './store'
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
As Dan Abramov mentioned in his insanely famous Egghead.io series, presentational component shouldn't be aware of Redux store and shouldn't use it directly. You should create something called container component, which will pass necessary state fields + action callbacks to your presentational component via properties.
I highly recommend to watch Dan Abramov's Egghead.io series if above concepts are not familiar to you. Patterns he is describing there are de facto standard style guide for writing React+Redux applications nowadays.
Edit 1
Some_File.js
import store from './redux/store.js';
function aFunction(){
var newState =store.getState();
console.log('state changed');
}
store.subscribe(aFunction)
I am assuming you have created store and reducers as redux expects.
~~~~~~~~~~~~~~~
Original Answer Starts
This is a sort of hack, I don't know what you are doing so I can't say you should or you should not do it, but you can do it this way. I have copy-pasted some of your code with some modifications.
Class XYZ extends React.Component{
componentWillReceiveProps(props){
//in your case this.props.storeCopy is redux state.
//this function will be called every time state changes
}
render(){
return null;
}
}
function mapStateToProps(state) {
return {
storeCopy : state
};
}
export default function connect(mapStateToProps)(XYZ);
Put this component somewhere at top, may just inside provider, whenever state changes this componentWillReceiveProps of this component will be invoked.
If you have a pure functional component then you can access the redux state directly like this:
import store from './redux/store';
function getStoreDetails() {
console.log(store.getState());
}
You don't want to store JSX in the state. Instead, store the model data for it, and loop through your data to print your elements!
you can do this:
state = {
tabs: [
{ tabID: '1', callbackFunctionName: callbackFunction1 }
]
}
And inside your render method, you can use these data about the tabs you have stored in your state to render your custom component.
render(){
const { tabs } = this.state;
return (
tabs.length > 0 && tabs.map((tab) => {
return (
<CustomComponent testCallback={this.tab['callbackFunctionName']} />
)
})
)
}
You shouldn't store the react component in the state, state just use for data:
For example:
state = {
tabs: [{ id: 1, content: "hello world", id: 1, content: "hello world 2" }],
};
And the in render() you can use that data to translate it to the react component:
render() {
const tabComponent = this.state.tabs.map((tab) => {
<CustomComponent
tabContent={tab.content}
id={tab.id}
testCallback={this.callbackHandler}
/>;
});
return (<>{ tabComponent }</>);
}
Hope it helps!!
When you are using Provider any component that is children of the Provider Higher Order Component can access the store properties though the use of connect function.
So you can add the following in any component that is a child of Provider and access the score prop
function mapStateToProps(state) {
return { score: state.score, status: state.status };
}
export default connect(mapStateToProps)(MyComponent)
However if this other component is a direct child of App component then you can also pass the score prop as a prop to this component from App like
<MyComponent score={this.props.score}/>
Provider component sets the context for all its children, providing the store in it. when you use the High Order Component(HOC) connect you can wrap any component and access the store through the provided mapStateToProps and mapStateToProps no matter how nested they are. You can also access the store using context context.store but this is not recommended. Using map functions and connect, similar to what you have with your App component, is the best approach.