In React JS, when should you use a store vs directly manipulating the view's state?
Asked Answered
E

2

5

Now I understand the concept of stores as the source of truth for a React app, but it seems that sometimes using stores is overkill, especially in UI-only situations.

For example, say I'm making an app which contains a list of movies. The app contains a search bar which lets you filter these movies according to their title. Should the value of this search bar (let's call it searchTerm) be contained in a store? Its only impact is on the list of movies shown, which is purely a UI feature. It won't be sent to the server or saved to local storage. So in my handleTextChange function, should I alert a store, or simply set the component's state:

Should it be this (using a store):

var Actions = Reflux.createActions([
    "searchChanged"
]);

var Store = Reflux.createStore({
    listenables: [Actions],
    getInitialState: function () {
        return data;
    },
    onSearchChanged: function (searchTerm) {
        this.trigger(data.filter(function (el) {
            return el.name.toLowerCase().indexOf(searchTerm.toLowerCase()) != -1;
        }));
    }
});

var View = React.createClass({
    mixins: [Reflux.connect(Store, "movies")],
    handleTextChange: function (e) {
        Actions.searchChanged(e.target.value);
    },
    render: function(){
        //Render here. Somewhere there is this input element:
        <input onChange={this.handleTextChange} type="text"/>
    }
)};

or this (not using a store):

var Store = Reflux.createStore({
    getInitialState: function () {
        return data;
    },
});
var View = React.createClass({
    mixins: [Reflux.connect(Store, "movies")],
    handleTextChange: function (e) {
        this.setState({searchTerm: e.target.value});
    },
    render: function(){
        var filtered = this.movies.filter(function (el) {
            return el.name.toLowerCase().indexOf(this.state.searchTerm.toLowerCase()) != -1;
        });

        //Render here using the filtered variable. Somewhere there is this input element:
        <input onChange={this.handleTextChange} type="text"/>
    }
}

The latter example is obviously simpler. Is there a good reason to use a store to filter the data? Or should the view have a searchTerm variable and perform the filtering in the render() function?

Ellen answered 16/3, 2015 at 11:19 Comment(1)
Depends a little how you cache your data in the store. At some point you would want to filter the data with your searchTerm. You can either do it in the component, let the store know which searchTerm is searched for, or send it as a parameter when fetching data. I am a fan of not sending to much information to the components which they do not need. So filtering as early as possible is an approach I have used, but can not say what is the best approach. If the dataset is small and you really do not need to cache the data, the component filtering would be ok.Kalliekallista
L
7

As your examples indicate, not using a store is simpler, and arguably correct in this case.

A weak question to answer is:

Does any other component need to know about the search results?

A better question is:

Might some other component need to know about the search results?

Consider that if you add paging through results, or even a simple header of "12 results found", then those components need to know the result and will need to get it from the store. Or perhaps you'll want to add a router and have the search update the url and the url change to drive the app.

If you can say for certain that ONLY subcomponents will ever care about a value, then state is OK.

Landri answered 16/3, 2015 at 18:59 Comment(0)
M
3

Both approaches are correct! But for your situation, filtering in component is better. Because searching result is calculable. The store should just keep the original data. The book "Developing the React edge" has an example for filterableForm, keep the search keyword in the view component is perfectly fine.

Mccullough answered 16/3, 2015 at 13:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.