How should filtering be properly done on a data array within a Redux reducer function?

I am trying to develop a function that filters an array based on a search input. The goal is for the filter action to trigger when there's a change in the SEARCH_TEXT. However, I'm facing confusion when it comes to handling the state when the delete key is pressed and the text field becomes empty. My initial thought was to use the initial state in the else statement, but I have doubts about whether this approach is correct or not. Returning just the state seems ineffective as it has already been manipulated in the if statement.

Here is a simple example:


    const initialState = ['hello', 'wahhh', 'yo'];

    export default function searchSimple(state = initialState, action) {
      switch (action.type) {
        case SEARCH_TEXT:
          if(action.text.length > 0){
            return state.filter(item =>
            item.startsWith(action.text)
            )
          }
          else {
            return state
          }
      }
    

Answer №1

Always keep in mind that the state serves as your ultimate "source of truth". Avoid discarding state based on a temporary filter, as once you do, those items are permanently removed. (To retrieve them, you would need to reset your state to the initialState, which may not be the preferred solution.)

A more effective approach is to retain your items list as it is and simply store the search text.

const initialState = {
    searchText: '',
    items: [ 'hello', 'wahhh', 'yo' ]
};

export default function searchSimple(state = initialState, action) {
    switch (action.type) {
        case SEARCH_TEXT:
            return Object.assign({}, state, {
                searchText: action.text
            });
    }
}

Although the filtered list is not stored in your state, the state provides all the necessary information to generate it.

If you are using React, you can set up your "smart component" with the following mapStateToProps() function:

function mapStateToProps(state) {
    const { items, searchText } = state.searchSimple;
    return {
        filteredItems: items.filter((item) => item.startsWith(searchText))
    };
}

If you require this filtered list in multiple places, consider creating a "selector" function, similar to the Redux shopping cart example shown at https://github.com/reactjs/redux/blob/master/examples/shopping-cart/src/reducers/cart.js

The selector function could be defined as follows:

export function filteredItems(state) {
    const { items, searchText } = state.searchSimple;
    return items.filter((item) => item.startsWith(searchText));
}

To explore a more advanced approach to selectors, take a look at the reselect library at https://github.com/rackt/reselect

Answer №2

Personally, I believe that the most appropriate location to filter data is within the selectors rather than directly in the reducers.

As stated in the Redux documentation:

Computing Derived Data

Reselect is a straightforward library for generating memoized, composable selector functions. Reselect selectors can efficiently compute derived data from the Redux store.

Currently, I am utilizing selectors to apply filtering and sorting to the data.

  1. Avoids data duplication in the state. No need to store duplicate copies of filtered items.
  2. Enables the same data to be utilized in various components with different filters, if needed.
  3. Allows for combining selectors to perform multiple data computations with existing application selectors.
  4. If implemented correctly, selectors become pure functions which are easily testable.
  5. Reusing the same selector across multiple components increases efficiency.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for stopping PHP echo from cutting off a JS string?

I encountered an issue with my code: <!DOCTYPE html> <html> <head> <title>Sign up page</title> <meta charset="UTF-8"/> </head> <body> <h1>Sign up page</h ...

What is the best way to turn off autocorrect in a textarea on IE11 without turning off spellcheck?

In my experience, disabling the spellcheck attribute seems to solve the auto-correct issue, but it also eliminates the underlining of misspelled words. <textarea id="TextArea1" spellcheck="false"></textarea> I prefer to keep spellcheck enabl ...

Retrieving the selected date from mat-datepicker into a FormControl

When creating a POST request to an API, I encountered an issue with the mat-datepicker field as it throws an error when inside the ngOnInit() call (since nothing is selected yet). Other fields like name, email, etc. work fine, but extracting a value from t ...

Implementing restify on a website that mandates user login authentication

Currently, I am operating a REST API server using restify. In addition, my front-end consists of angularjs with html, css, and js files hosted on an Apache webserver. The next step is to implement user login authentication for this webapp. Access to the w ...

What is the most efficient way to use jQuery to retrieve the count of tags associated with a variable

I am trying to filter my data retrieved from ajax using a function. Here is the initial code: var csvf = data.filter(function (el) { return ['TRUCK_CPX'].indexOf(el.TAG) >= 0 && ['CA5533'].indexOf(el.Chave) >= 0 }); Now ...

End the child process.execution after a specific amount of time

I have been searching for information on child process waiting time or response waiting time, but I haven't found anything useful. I'm in need of something like that, so I hope someone can assist me. When I look at the code below, I am printing ...

What is the best way to process an API call entirely on the server without revealing it to the client?

Seeking guidance on a technical issue I've encountered. On my website, x.com, a form submission triggers an API call to y.com, yielding a JS hash in return. The problem arises when Adblocker Plus intercepts the content from y.com, causing it to be bl ...

Establishing a standard flatiron-director route (within the element) using the polymer core-pages component

This particular query is closely linked with issues surrounding the usage of flatiron-director/core-pages SPA in conjunction with route-specific JavaScript functions and default routes. While the solution proposed may be effective, my limited expertise in ...

Difficulty arises when transferring files in Node.js from one directory to another

Attempting to use node.js to transfer files from the currentFolder(root of project)/node_modules/mime/ to currentFolder(root of project)/files/, encountering an error: events.js:85 throw er; // Unhandled 'error' event ^ Error: ...

Is it possible to use useDispatch asynchronously multiple times?

I am facing an issue where using useDispatch twice to update my todos and then change my login status is causing the second dispatch to overwrite my list of todos with an empty object []. Both actions work independently, but not when executed sequentially. ...

Is there a way for me to determine when the modal animation has completed?

I'm currently using the modal feature in twitter-bootstrap and I am curious about how long it takes for the modal to appear before triggering an alert. To better illustrate my point, you can check out this example: HTML <button id="mod" class="b ...

How can jQuery be utilized to dynamically update the text in a navbar?

<div id="page1" data-role="page"> <div data-role="header" data-position="fixed" align="center"><img src="img/VAWE-long-300x30-transparent.png" width="300" height="30" alt="" /></div> <div data-role="content" style="margin ...

The use of "app.use("*") appears to be triggering the function repeatedly

app.use("*", topUsers) is being invoked multiple times. The function topUsers is called repeatedly. function topUsers(req, res, next){ console.log("req.url", req.url) findMostUsefullReviewsAggregate(6) .then(function(aggregationResult){ ...

Implement ES6 classes for managing state in the vuex store within a Nuxt application

After setting an ES6 class to the state in my vuex store in nuxt, I encountered the following warning: WARN Cannot stringify arbitrary non-POJOs EndPoint However, when I use an object as the state, it works without any warnings. So the question arises ...

Navigating through the map function within Protractor

In my Angular application, I have implemented a timeline that displays event dates with their respective descriptions. Below is the HTML source code for this feature: <!-- timeline --> <h4 class="font-thin m-t-lg m-b-lg text-primary-lt">Hi ...

Using a carousel component in Bootstrap

Just starting out with this, trying to customize Bootstrap to change slides automatically. I followed the documentation at https://getbootstrap.com/docs/4.3/components/carousel/ but for some reason, the slides aren't changing on an interval, even thou ...

Tips for employing numerous if-else conditions utilizing the ternary operator in jsonpath-plus?

JSON { "customer":{ "address":{ "stateRegion":"", "stateRegionCode":"" } } } Code "address.state_code": "$.customer.address.[stateRegion ? state ...

Utilize JSON data from a service to populate a Bootstrap Modal

I need assistance with populating a Modal using the JSON values I received from a service call. The object structure is simple and understandable, like this: var object = [ {Value1: "Val1", Value2: "Val", Value3: [{a:"a",b:"b"}] }] The ajax call looks ...

Handling MySQL insertIds and errors in Node.js using MySQL is a crucial aspect of

I am struggling to handle errors and retrieve the insertId after creating a new row in my database using code from the official page of mysqljs/mysql. How can I modify my code to achieve this? var post = {deviceImei: deviceInformation.deviceImei, created_ ...

"Can you provide guidance on displaying a form for a specific element based on its unique ID

I am trying to display the edit form when clicking on a specific image, but it is currently showing for all tasks. I need help in figuring out how to make it show only for one task. I attempted to use useState to change the boolean value "active" to show ...