I'm trying to learn from reading this app's code, and I am confused how you get dispatch from the props in this line of code:
_handleSubmit(e) {
e.preventDefault();
const { email, password } = this.refs;
const { dispatch } = this.props;
dispatch(Actions.signIn(email.value, password.value));
}
https://github.com/bigardone/phoenix-trello/blob/master/web/static/js/views/sessions/new.js#L17
Hoping someone can explain how calling this.props will return a dispatch?
react-redux is a library that helps components get values from the Redux store in a predictable and performant way. The main tool it provides is a function called connect, which wraps Redux components providing them with store values as props. The key part of the code you link to is at the bottom: https://github.com/bigardone/phoenix-trello/blob/master/web/static/js/views/sessions/new.js#L70-L74.
Say you have a value in the Redux store named counter. You want your component CounterDisplay to know about this value, and update when it changes:
class CounterDisplay extends Component {
render () {
const { counter, dispatch } = this.props
return (
<div>{counter}</div>
)
}
}
Those variables are going to be undefined unless you've explicitly put the values into props the 'old fashioned way':
<CounterDisplay counter={1} dispatch={() => {}} />
That's where connect comes in. It knows about the Redux store (often using another component called Provider) and can place values from it into the props of the component it's wrapping. It returns what's called a Higher Order Component (HOC): one that wraps another to perform a specific function, in this case connection to the store.
Here's how we'd get the counter value into props:
function mapStateToProps (state) {
// Slightly confusingly, here `state` means the entire application
// state being tracked by Redux... *not* CounterDisplay's state
return {
counter: state.counter
}
}
export default connect(mapStateToProps)(CounterDisplay)
So instead of exporting CounterDisplay itself, we export the HOC. In addition to counter, connect will also automatically insert the dispatch function into props so we can make use of it in the component. That's the behaviour you're seeing in the source you're reviewing.
const { dispatch } = this.props; is just deconstructing this.props.dispatch into a dispatch variable so it's used from props and where do they come to props? From react-redux connect:
export default connect(mapStateToProps)(SessionsNew);
connect is just Higher Order Component which basically connects your component with the store. As part of this process it puts dispatch into component's props
Edit:
The main idea is that connect is a function that takes whatever components and extends it's props with dispatch property (it returns another react components that wraps your component). You can also map some properties from state to your component and bind actions with dispatch using mapDispatchToProps and mapStateToProps
Just an example of destructuring assignment. See more here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
Related
I have tried pass value from parent to grandchild component, and it works. While I am thinking if there is another simpler or other way of passing props in shorter path.
What I did is quite cumbersome in codesandbox
There may be a common problem in react world called prop drilling by passing data to children only using props.
I would recommend only 2-level passing, if you need pass data deeper then you probably doing something wrong.
Use one of popular state management library (if your project is big) or React context (which is awesome)
Create a folder called /contexts and put contexts there. The structure of files can be like shown below:
First you need to create a context itself
type ClientContextState = {
data: User;
set: (data: User) => void;
logout: () => void;
};
// empty object as a default value
export const UserContext = createContext<UserContextState>({} as UserContextState);
Then create a Provider wrapper component
export const UserProvider = ({ children }: Props) => {
const [data, setData] = useState<User>({});
const sharedState = {
data,
set: setData
logout: () => setData(null)
}
return <UserContext.Provider value={sharedState}>{children}</UserContext.Provider>
});
You may also want to have an alias of useContext hook:
export const useUser = () => {
return useContext(UserContext);
};
After all this whenever you wrap your components or app to <UserProvider>...</UserProvider> you can use our hook to access data and methods form sharedState from any place you want:
export LogoutButton = () => {
const {data, logout} = useUser();
return <Button onClick={() => logout()}>Logout from {data.name}</Button>
}
Whenever you want to pass props or data from Grandparent to child component, always use react-redux. This is useful to maintain the state and access the data from anywhere/any component.
Another way is to use useContext hooks which you can use to pass the props
Following are the steps to use useContext hooks
Creating the context
The built-in factory function createContext(default) creates a context instance:
import { createContext } from 'react';
const Context = createContext('Default Value');
The factory function accepts one optional argument: the default value.
Providing the context
Context.Provider component available on the context instance is used to provide the context to its child components, no matter how deep they are.
To set the value of context use the value prop available on the
<Context.Provider value={value} />:
function Main() {
const value = 'My Context Value';
return (
<Context.Provider value={value}>
<MyComponent />
</Context.Provider>
);
}
Again, what’s important here is that all the components that’d like later to consume the context have to be wrapped inside the provider component.
If you want to change the context value, simply update the value prop.
Consuming the context: Consuming the context can be performed in 2 ways.
The first way, the one I recommend, is to use the useContext(Context) React hook:
import { useContext } from 'react';
function MyComponent() {
const value = useContext(Context);
return <span>{value}</span>;
}
Generally it's helpful to consider whether moving state down the hierarchy would be the simplest route. That means lifting the component instantiation to a place closer to the state being used. In your example, that could mean Component_data is used inside Component and passed to its children there, removing one step in the nested data flow. Even better, would be that Child.a accesses Component_data.A directly.
In a real app with cases where accessing the data directly is less feasible, a solution I lean towards is using Context to set data in the parent that retrieves it, and then I can access it however deeply nested the component might be that needs it.
i.e. in App I would create the Context provider, and in ChildA I access it via useContext hook.
Further reading
https://reactjs.org/docs/context.html
https://overreacted.io/before-you-memo/#solution-1-move-state-down (this post is about an alternative to using useMemo but has an illustrative example of why moving state down is a good thing)
I'm new to React and still struggling in understanding in using redux with React.
For example, below is some code :
const mapStateToProps = (storeData) => ({
editing: storeData.isEditMode;
})
const mapDispatchToProps = {
saveCallback: xxx
}
const connectFunction = connect(mapStateToProps, mapDispatchToProps);
export const ProductDisplay = connectFunction(
class extends Component {
render() {
if (this.props.editing) {
...
} else {
...
}
}
}
)
and a component that uses ProductDisplay
export default class App extends Component {
render() {
return <ProductDisplay/>
}
}
Let's say storeData.isEditMode is changed by other component, so the wrapped component's props.editing is changed. As we know that the only way to trigger update process is to use setState() but how does react know that ProductDisplay component needs to be updated since there is no setState() method involved?
The connect function generates a wrapper component that subscribes to the store. When an action is dispatched, the wrapper component's callback is notified. It then runs your mapState function, and shallow-compares the result object from this time vs the result object from last time (so if you were to rewrite a redux store field with its same value, it would not trigger a re-render). If the results are different, then it passes the results to your "real" component" as props.
Dan Abramov wrote a great simplified version of connect at (connect.js) that illustrates the basic idea, although it doesn't show any of the optimization work.
update
React-Redux v6.0.0 made some major internal changes to how connected components receive their data from the store.
For more details: https://spin.atomicobject.com/2018/04/02/redux-rerendering/
I'm following a react tutorial and I had a few questions.
I am confused about this function:
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchWeather }, dispatch)
}
I want to breakdown each part of this function.
How do you hook up the action creator to a container? How is this.props.fetchWeather working code? Is this responsible for that?:
function mapDispatchToProps(dispatch) {
If so, what is this doing?
return bindActionCreators({ fetchWeather }, dispatch)
Is that responsible for making sure that the action object that is returned from the action creator flows down into the middleware and reducers?
What is this doing then:
function mapDispatchToProps(dispatch)
Is mapDispatchToProps just convention or is it part of react?
Lastly, what is this export doing:
export default connect(null, mapDispatchToProps)(SearchBar);
What is the connect doing? What does it do for me?
Here is my whole code for reference:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchWeather } from '../actions/index';
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { term: '' };
this.onInputChange = this.onInputChange.bind(this);
this.onFormSubmit = this.onFormSubmit.bind(this);
}
onInputChange(event) {
this.setState({ term: event.target.value });
}
onFormSubmit(event) {
event.preventDefault();
this.props.fetchWeather(this.state.term);
this.setState({ term: '' });
}
render() {
return (
<form onSubmit={this.onFormSubmit} className="input-group">
<input
placeholder="Get a five-day forecast in your favorite cities"
className="form-control"
value={this.state.term}
onChange={this.onInputChange}
/>
<span className='input-group-btn'>
<button type="submit" className="btn btn-secondary">
Submit
</button>
</span>
</form>
);
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchWeather }, dispatch)
}
export default connect(null, mapDispatchToProps)(SearchBar);
A very concise answer would be:
mapStateToProps() is a utility which helps your component gets updated state(which is updated by some other components)
mapDispatchToProps() is a utility which will help your component to fire an action event (dispatching action which may cause a change of application state)
bindActionCreators() is mostly used when you want to pass some action creators down to a component that isn't aware of Redux, and you don't want to pass dispatch or the Redux store to it.
<Provider> makes the Redux store available to the your "connected" React components.
connect() is a higher-order component (HOC) that lets you inject Redux state into a regular React component.
Let's dive a bit deeper
ReactJS - JS library for building user interfaces.
Redux - JS library for managing application state.
Putting them together using react-redux:
If we want to link our React application with the Redux store, we first have to let our app know that this store exists. This is where we come to the first major part of the react-redux library, which is the Provider.
A Provider is a React component given to us by the react-redux library. It serves just one purpose: to “provide” the store to its child components.
Provider
Makes the Redux store available to the connect() calls in the component hierarchy below. Normally, you can’t use connect() without wrapping a parent or ancestor component in <Provider>. So ultimately connect does just that, it connects your React app to the Redux store.
//This is the store we create with redux's createStore method
const store = createStore(todoApp, {})
// Provider is given the store as a prop
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('app-node')
)
Props
store (Redux Store): The single Redux store in your application.
children (React Element): The root of your component hierarchy.
Explanation and usage of the Connect function:
Now that we have “provided” the redux store to our application, we can now connect our components to it. We established previously that there is no way to directly interact with the store. We can either retrieve data by obtaining its current state or change its state by dispatching an action (we only have access to the top and bottom component of the redux flow diagram shown previously). This is precisely what connect() does.
To use connect(), you need to define a special function called mapStateToProps that describes how to transform the current Redux store state into the props you want to pass to a presentational component you are wrapping.
In addition to reading the state, container components can dispatch actions. In a similar fashion, you can define a function called mapDispatchToProps() that receives the dispatch() method and returns callback props that you want to inject into the presentational component.
Simple explanation and a basic example of mapStateToProps
The Store is a box, which contains the entire application state. Imagine that this box is in an unknown location.
The components need to take some of the things out of the box but they only need some of the things stored in it. The components know what they need from the box but they don't know where the box is.
The mapStateToProps function is a filter used to select which things in the box are required by the component. The selected things become the component properties.
The mapStateToProps function is not enough because it selects the required things in the box but it doesn't know where the box is located.
The connect function knows where the box is located and passes it to the mapStateToProps function so it can grab what it needs.
Conclusion: mapStateToProps simply returns a specified part of the current state. mapStateToProps get the data that is fed to its component.
const mapStateToProps = (state) => {
return { things: state.things }
};
So now we're able to use that part of the state as props -> this.props.things
But what if the component wants to change the state? That is where mapDispatchToProps comes in.
Simple explanation and a basic example of mapDispatchToProps
As implied in its name, this function directs the dispatching or sending of an action by pointing it to an action creator. For example:
const mapDispatchToProps = () => {
return {
addThing: addThing,
doAnotherThing: doAnotherThing
}
}
mapDispatchToProps takes the dispatch functions in your component and executes them against the Redux reducer when that function is fired. Remember that Props aren’t just objects, they can also be functions. This is where mapDispatchtoProps applies. MapDispatchToProps allows for you to dispatch state changes to your store. An example would be a button click that triggers a refresh or an automatic loading of data once the component is mounted.
The action creator is made available to the component as a prop, which is usually tied to an event handler function contained in the component:
handleOnClick() {
this.props.addThing();
};
However, returning the action creator is only one part. We also want the send that returned action to the store. How do we do that? We use Redux’s bindActionCreators().
Simple explanation and a basic implementation of bindActionCreators():
Turns an object whose values are action creators, into an object with the same keys, but with every action creator wrapped into a dispatch call so they may be invoked directly.
Normally you should just call dispatch directly on your Store instance. If you use Redux with React, react-redux will provide you with the dispatch function so you can call it directly, too.
The only use case for bindActionCreators is when you want to pass some action creators down to a component that isn't aware of Redux, and you don't want to pass dispatch or the Redux store to it.
To implement it, we:
import { bindActionCreators } from 'redux';
...
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
addThing: addThing,
doAnotherThing: doAnotherThing
}, dispatch);
};
The bindActionCreators() function accepts the action creator and the store’s dispatch function as arguments, and returns a dispatch function that uses the return value of the action creator as its arguments.
Once again, tying this all together is the connect() function, in which we pass mapDispatchToProps as a second argument. For example:
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
which will export a component that can both get the current state from the store, and dispatch an action to the store to trigger and update to the state.
Now, let's put it all together with a little TodoItem.js React functional component:
import { connect } from 'react-redux'
const TodoItem = ({ todo, destroyTodo }) => {
return (
<div>
{todo.text}
<span onClick={destroyTodo}> x </span>
</div>
)
}
const mapStateToProps = state => {
return {
todo: state.todos[0]
}
}
const mapDispatchToProps = dispatch => {
return {
destroyTodo: () =>
dispatch({
type: 'DESTROY_TODO'
})
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(TodoItem)
mapStateToProps and mapDispatchToProps are both pure functions that are provided the stores “state” and “dispatch” respectively. Furthermore, both functions have to return an object, whose keys will then be passed on as the props of the component they are connected to.
In this case, mapStateToProps returns an object with only one key: “todo”, and mapDispatchToProps returns an object with the destroyTodo key.
The exported connected component provides todo and destroyTodo as props to TodoItem functional component
I'm still new to react/redux, after getting something like this to function
User.js
class User extends React.Component {
componentWillMount() {
this.props.fetchUser(.....);
}
render() {
return (
<Profile />
)
}
export default connect(null, {fetchUser})(User);
Profile.js
class Profile extends React.Component {
render() {
const { user } = this.props
return (
<h1>{user.profile.name}</h1>
)
}
const mapStateToProps = state => ({
user: state.store.user
});
export default connect(mapStateToProps, {})(Profile)
actions.js
export const fetchUser = (.....) => dispatch => {
fetch()
.....
}
reducers.js
case FETCH_USER:
return {
...state,
user: action.payload.user
};
As I understand it, the User component calls an action (fetchUser) from connect on componentWillMount(). That action calls an api, gets the data and the reducer adds that to the store within the state. The Profile component can then use connect to map the data from fetchUser in the store and display that data.
After reading some tutorials including https://github.com/reactjs/redux/blob/master/docs/basics/UsageWithReact.md
It looks like things can be simplified a bit without using classes.
If I were to change the User and Profile components to a more functional way, how would I do it?
eg.
const User = () => {
return (
<Profile />
)
}
how do I dispatch the fetchUser action and how do I simulate it to be called with the flow of componentWillMount()?
or am I just over complicating things?
There is also a way to support lifecycle methods in functional components.
https://www.npmjs.com/package/react-pure-lifecycle
import React from 'react';
import lifecycle from 'react-pure-lifecycle';
// create your lifecycle methods
const componentDidMount = (props) => {
console.log('I mounted! Here are my props: ', props);
};
// make them properties on a standard object
const methods = {
componentDidMount
};
const FunctionalComponent = ({children}) => {
return (
<div>
{children}
</div>
);
};
// decorate the component
export default lifecycle(methods)(FunctionalComponent);
I think you should keep using statefull components with redux...
https://medium.com/#antonkorzunov/2-things-about-purecomponent-you-probable-should-know-b04844a90d4
Redux connect — is a PureComponent.
Yes — a very important thing, a HoC for a molecule is a pure one. And works even inside other pure components. And gets store from a current context.
Same is working, for example, for styled-component — you can wrap it with PureComponent, but it will still react to Theme changes.
Solution is simple — bypass logic, use old school events bus, subcribe, wait and emit events.
Styled-componets:
componentWillMount() {
// subscribe to the event emitter. This
// is necessary due to pure components blocking
// context updates, this circumvents
// that by updating when an event is emitted.
const subscribe = this.context[CHANNEL];
this.unsubscribe = subscribe(nextTheme => { <----- MAGIC
React-redux:
trySubscribe() {
if (shouldSubscribe && !this.unsubscribe) {
this.unsubscribe =
this.store.subscribe(this.handleChange); <----- MAGIC
}
}
componentDidMount() {
this.trySubscribe();
}
Thus, even if parent Pure Component will block any update enables you to catch a change, store update, context variable change, or everything else.
So — something inside pure components is very soiled and absolutely impure. It is driven by side effects!
But this bypass straight logic flow, and works just differently from the rest of application.
So — just be careful. And don’t forget about magic.
Aaaand….
And this is a reason, why any redux store update will cause redraw in each connected component, and why you should use reselect just next to connect HoC —
to stop unnecessary change propagation.
But you should read this from another point of view:
redux-connect is a source of a change propagation.
redux connect is the end of a change propagation. It is still PureComponent.
And this leads to quite handy thing — you can control change propagation with redux-connect only. Just create a boundaries for a change. Lets talk about this in another article.
Conclusion
Pure components keep your application fast. Sometimes — more predictable, but often — less predictable, as long they change the way application works.
Stateless components are not pure, and may run slower than PureComponents by any kind.
But… if you very wish to create a fast application with good user experience — you have to use Pure Component.
No choice. But, now — you know hidden truth, and knew some magic…
React recommends that ajax request be made in componentDidMount(), rather than in componentWillMount(). For more info on this, read this post.
Since you want to make ajax requests in componentDidMount(), you need a class. There are two ways of writing component definitions: functional component and the class component. Functional components are more concise, but you don't get component lifecycle methods like componentDidMount(). Think of it as just a render function that takes props as inputs and outputs DOMs (in JSX). To override those lifecycle methods, you need to define them as a class.
If you want to use Redux, and want to make ajax requests in a Redux action, you should import the action creator function (fetchUser(..) in your case) that makes the ajax request, and dispatch(fetchUser(..)) in componentDidMount(). connect(..)ed components get dispatch(..) function passed to it by Redux store.
If you want to see how it's done in other redux apps, see the official example apps in the redux.js repo, paying attention to actions and containers: https://github.com/reactjs/redux/tree/master/examples
In Your case you can continue with statefull components no wrong in that
,If you need to go with functional way
There is a work arround
https://github.com/mobxjs/mobx/issues/162
Suggestion
Calling the api in componentDidMount will make sense than
componentWillMount , Because you can show the user something is
fetching.
I think,User component is designed nicely.It will act as a container for Profile to provide the Data.
Instead of making Profile component class oriented,it should be Stateless.
Lets User component pass the required data for Profile component.
You don't need to connect Profile component using redux-connect.Just render it as a Child component of User.
Profile
const Profile = (props) => {
const {user, likeProfile} = props;
//likeProfile()//call like this using dom event or programmatically.
return (
<h1>{user.profile.name}</h1>
)
}
You need to make some changes in User component.
Get the state for Profile component via mapStateToProps.
class User extends React.Component {
componentWillMount() {
this.props.fetchUser(.....);
}
render() {
const {user, likeProfile} = this.props;
return (
<Profile user= {user} likeProfile={likeProfile} /> //passed the user data to Profile component vua User
)
}
Map the user state for Profile in User connect.
const mapStateToProps = (state)=>{
return{
user : state.somereducerkey.user //this will be accessible in Profile via props { user}
}
}
export default connect(mapStateToProps, {fetchUser, likeProfile})(User);
I am new to react and redux xo my questions will sound basic.
What does dispatch means? I am referring to the term dispatching an action.
Why do we need mapDispatchToProps to store actions on redux? We can simply import an action and use it. I have a scenario in which I have to load data when a component is mounted.
#mariazahid mapDispatchToProps will bind the action to your component so that you can pass it down to your presentation components. This is a pattern that is normally used within using Redux with React.
You can import your action and just dispatch the action, but in most scenarios a container -> component pattern is used. A container is where the actions are mapped to and the state and the only goal of this component is to pass this data down to components that are used for presenting that data.
When working in teams, it's a pattern that is easily adoptable. Instead of importing actions from left right and center, you will just have to be aware of the container and how it passes the required actions/data down to the children.
From an implementation perspective, dispatch is just a method that is used to communicate with your reducers
Let say that your action looks something like this
function myAction() {
return { type: 'MY_ACTION' };
}
You're trying to communicate with the reducer that responds to the action type 'MY_ACTION'
In your mapDispatchToProps you'd typically do something like this;
function mapDispatchToProps(dispatch) {
return { actions: bindActionCreators(myActions, dispatch) }
}
Effectively, you're wrapping(binding) your actions to the dispatch method;
function bindActionCreators(actions, dispatch) {
// this is a very trivial implementation of what bindActionCreators does
let wrappedActions = {};
Object.keys(actions).forEach(action =>
// for every action, return a function that calls dispatch on the result of what your action returns
return function(...args) {
// remember here that dispatch is the only way you can communicate with the reducers and you're action's type will determine which reducer responds to return the new state
return dispatch(actions[action](..args));
}
);
}
And so, these "bound" actions are now assigned to a props.actions in your component.