How to Cross-Access State Values
Mar 5, 2020 • 11 Minute Read
Introduction
React is a popular JavaScript libraries used to create user interfaces using component-based architecture.
For managing application-level data, Redux can be implemented with different platforms, such as Angular, React, or Vue.js, to manage the global state data.
What is React-Redux?
The Redux library allows us to interact with the global store object, which consists of the global state object that can be used to access the data into the multiple components.
React-Redux is a standalone library that allows us to use Redux with a React application. They are generally used together to access the global state data.
The advantages of using React-Redux include:
- Better component reusability due to data access across the application
- Official library to use Redux with a React application
- It skips the unused data and can use the useful data into the specific component
- Global state object so that it can be accessible to multiple components
- Giant community support
Access State Data into the Component
The React-Redux library provides a set of APIs that allows us to dispatch actions from the components and access the updated or modified data from the global store object.
React-Redux's <Provider> component uses the <ReactReduxContext.Provider> to put the Redux store and the current store state into context, and the connect() method uses <ReactReduxContext.Consumer> to read those different values and handle data updates.
We use <provider> to specify the application context like this.
<Provider store={store}>
<App />
</Provider>
The store is the global state object—a collection of reducers that hold the data of separate state, e.g., employee, student, teachers, and so on.
The method used to connect the components to the Redux store is called connect (), and it allows us to access the global state data into the component.
The basic syntax of the connect() method should look like this.
function connect(
mapStateToProps?,
mapDispatchToProps?,
mergeProps?,
options?
)
This syntax accepts the different arguments that accept mapStateToProps and mapDispatchToProps, widely used arguments to access the state values and dispatch the actions from the current component.
For example, if we want to access employee records from the global state object, we can use it like this.
import React, { Component } from 'react';
import { connect } from 'react-redux';
class EmployeeMaster extends Component {
render() {
return (
// Return modified elements
)
}
};
const mapStateToProps = state => {
return {
// To get the list of employee details from store
employee: state.employee.data
}
};
export default connect(mapStateToProps, null)(EmployeeMaster);
Here in this example, we have consumed one argument along with the connect() method: mapStateToProps, which is used to access the state values into the current component as the props value.
Now, if we want to access the employee data, then we can use it like this.
class EmployeeMaster extends Component {
render() {
// Accessing state values as props
const { employee } = this.props;
return (
// Use employee data here
)
}
};
We have accessed employee as the props because when we access the global state objects or values, we cannot modify it; hence it acts as a prop for the current component.
We can also use multiple state values and divide all the state values as separate props like this.
const mapStateToProps = state => {
return {
// to get the list of employee, student and teachers details from the store
employee: state.employee.data,
student: state.students.data,
teachers: state.teachers.data
}
};
As you can see, we have three different keys as props that fetch the specific state object from the global state object and can use those objects into the current component.
We can also use ownProps if we want to access different props values from the same component as a separate argument like this.
const mapStateToProps = (state, ownProps) => {
return {
// To get the list of employee, student and teachers details from the store
employee: state.employee.data,
student: state.students.data,
teachers: state.teachers.data,
temp: ownProps
}
};
The ownProps argument allows us to merge the props coming from the current component, and it wraps the final source of props into the newly added props object.
Access Cross-State Data to React with Redux
As we have learned, the Redux store maintains the global state object ,which combines the data from the different reducer and makes it available for all the components across the application.
Accessing cross-state data may be required sometimes because we have to manipulate multiple state values at a time. For example, we may need to access the student data into the teacher component where each teacher can assign to the class of students.
Note: Data coming from different reducers may or may not be useful ultimately, so we have to filter it based on our functional requirements.
For that, we can make use of the library reselect, which allows us to store the minimal possible state values.
The selectors are efficient and compatible in nature so they can be useful to others as an input value. Now, let's install the reselect library.
npm install --save reselect
We can create the new selector using the method createSelector(), which we import like this.
import { createSelector } from 'reselect';
The basic syntax of the reselect should look like this.
// Basic selector
const selector_name = (state) => state.parent.key_value
As you can see in the syntax, we can access the specific state value by using the specific key name that we are going to consume into the component.
Then we can create the selector function that accepts the first argument as a selector name, and another argument is a function that manipulates the state value and returns the updated values just like this.
// Basic selector
const selector_name = (state) => state.parent.key_value
// Reselect function
export const function_name = createSelector(
[ selector_name ],
(func) => reurn_anything
)
Here, the reselect function accepts the selector name as the first argument, and then after the state value will be modified into the function so that we will get the required values into the component rather than the complete state object.
For example, if we want to create the selector for three different objects, such as students, teachers, and employees, then the selector and selector functions will look like this.
const getStudentsRecords = (state) => state.students.data;
const getEmployeesRecords = (state) => state.employees.data;
const getTeachersRecords = (state) => state.teachers.data;
// Students reselect function
export const getStudents = createSelector(
[getStudentsRecords],
data => data
);
// Employees reselect function
export const getEmployees = createSelector(
[getEmployeesRecords],
data => data
);
// Teachers reselect function
export const getTeachers = createSelector(
[getTeachersRecords],
data => data
);
Here, initially, we have created three different selectors and used all those selectors as an argument along with the reselect function like this.
// Students reselect function
export const getStudents = createSelector(
[getStudentsRecords], // selector as first argument
data => data
);
As you can see in the above example, we have a selector called getStudentsRecords, which represents the students' data; hence we are allowing only student records to be selected from the complete state object.
Now once we use the selector getStudents, we will get the complete data of the student object from the global state object.
Access Multiple State Values Using the Selector Function
We have seen an example of accessing a single state value, but we can also use multiple state values and manipulate them like this.
const selector_name = createSelector(
state => state.values.value1,
state => state.values.value2,
(value1, value2) => value1 + value2
)
In the above example, we have accessed different state values, and at the end of the callback function, the different state values are concat with each other and return a new set of data.
Access and Use Selectors from Components
After creating the various selector and selector functions, we should use those selectors into our component so it can be used as a prop into the existing component.
To access the selectors, we should understand mapStateToProps, which is used to take the entire state object and picks out the specific values.
Without the selector functions, we can access the state values like this.
const mapStateToProps = state => {
return {
employee: state.employee.data
}
}
export default connect(
mapStateToProps,
null
)(TestComponent)
As you can see, we are accessing the employee state object as state.employee.data, so if you update the employee object into the global state object, then it will be painful to update into all the required files.
But reselect makes it possible to select only the appropriate and useful data to be fetched from the global state object into the component, like this.
const mapStateToProps = state => {
return {
students: getStudents(state),
employees: getEmployees(state),
teachers: getTeachers(state),
}
}
export default connect(
mapStateToProps,
null
)(TestComponent)
Using this approach, the next time we update the state values, we need to update the selector so it will be reflected in all the components where those selector functions are being used.
Conclusion
Accessing the cross-state value from the component is a crucial task to manage the maintainability of the state data across an application.
In this guide, we have learned to make use of the reselect library to access the cross-state values from a component, which directly impacts app performance by fetching the required state values only. Hope this guide was helpful.