Flux + React: when to keep state of visual components at store - javascript

Sometimes it's not obvious: where I should keep state of React view, i.e. active tab, selected option, toggler value, is input validated flag?
Actually there are two options:
Throw an action and keep that data in store
Keep that data as view's state
Which of them is better? Are stores intended only for data from server?
My considerations:
That's bad to keep that data in store, because that lead to chain of actions. Example: you need to download data on tab selection - so you trigger an action NEW_TAB_SELECTED and from the store which handle it trigger a new action DOWLOAD_TAB_DATA.
Keeping data in view allow to avoid the first action (NEW_TAB_SELECTED) and avoid action chains. But how to keep selected tab if I want to leave this view?

Things that should be kept in the component's state are things which only affect that component.
So, for example, if you have a component which opens to reveal more content then the isOpen flag can be kept in state because it's internal to the component.
If the information is not part of the component (such as the text of a message and whether the message has been read) then it should be kept in a store and circulated through the app as needed.
Changing the state of a component will cause it to redraw, so try to keep state to the minimal possible representation of its state, and only store those properties in this.state.
Therefore, from what I can gather from your question, I'd suggest keeping active tab, selected option, toggler value and whether the input is validated in this.state. They are all properties of the component but don't affect any other components. I'd keep the data which populates the views in a store. I'd keep the flags which indicate the state of the view in this.state.
Hope that helps.

Related

React: how to monitor the focus state of another component

I have 2 separate components that are very "far" from each other (no parent-child relationship to pass props around):
A component that does a count-down and navigates away when timer is hit.
A text field down below the page.
I want to stop the timer when the user is editing the text field.
Besides saving an "isEditing" state into Redux or window (or some state management) from component #2, and monitoring that state from component #1, are there any standard React way to achieve this?
Perhaps there is a way for a ref to listen to another ref's property change, such as focus?

React-Redux design approach - Redux action or local function for two-way binding of editable text field

Good day,
I have read through a number of SO posts which were helpful in progressing my problem, but I still have not found anything concrete information on whether there is an established method for the following scenario I face:
I have an application that allows a user to either:
Add a graph; or
Edit an existing graph
When either the 'add graph' button or the 'edit graph' button is clicked, a side-drawer opens. The fields for for the x-axis label, y-axis label and chart title are either blank (for case (1)) or have fields already populated (for case (2)). The fields themselves are editable text input fields.
Currently, when a graph is added, I create a UUID for the graph and then the user can enter text into the fields, and the click save. When save is clicked a Redux action is dispatched to save the content of the fields in the Redux store. The two-way is binding between the text field values and the local state which contains those values initially. Once the 'save' button is clicked and the Redux action fires, the local state is set to empty strings for each field. So Redux is only used when we actually hit the save button.
Now, when an existing graph is selected, I populate the text fields of the side-drawer with the Redux state via mapStateToProps. I use two way binding that is between the text input fields and the Redux store via Redux actions incorporating debouncing to try reduce the number of actions fired off. This means that essentially a slow typer would cause a Redux action to be fired for every key stroke when editing the fields.
I do not like that we have different methods of two-way binding depending on whether the user clicks 'edit' or 'add'. I also do not like having so many Redux actions fired off for something as simple as adding or removing a letter from a word.
I then went through SO and the Redux documents and found that in general people advised that one should not initialise local state with Redux state via props. What I wanted to do was actually copy the Redux state describing the existing content of the fields (when edit is clicked) into the local state and then have the two-way binding in the local state, similar to what I have for the Case (1) scenario. This then eliminates numerous Redux actions being fired off in quick succession and I can use the same two-way binding irrespective of whether 'add' or 'edit' is clicked. But after reading through the documents it seems this is a bad idea for in the case that there is a an unexpected re-render and the local state is reset mid-way through editing, as well as having two sources of truth.
Having the two-way binding in the local state for an added graph and in Redux for an edited graph is quite confusing and does not provide clean and consistent code for those who will need to maintain this code base. Is there a established method that provides for such a scenario? I imagine editing posts on social media would be a similar context to the problem I am facing.
I have not provided my code as it is not a coding question in itself but rather a design problem and my Redux code is split over several files. But I am happy to provide the code if it helps.
First of all, good question. This is a question that comes up quite a bit, especially with how Redux works. Redux has always, in my opinion, forced the question of, "where should this state live?". Now, I know that the docs do give a pretty clear delineation on what state should live in Redux, but when you begin creating an application, it can still be challenging.
For your particular problem, I would choose one or the other - either use local state for both add and edit or use Redux for both add and edit. To have one in Redux and one in local state is, like you said, confusing. Personally, if there is not a lot of data and not a lot of business logic/computational code, I would use local state. It is okay to use state from Redux to set your initial state, i.e., mapStateToProps -> useState() (if you are using hooks). Once you populate your local state from Redux, the only other time that data reaches Redux is when your component is finished working with that data. I would not be worried about "unexpected re-render and the local state is reset mid-way through editing". If that happens, you have a bug that needs to be fixed and that is not the fault of Redux and passing state to the component.
I hope this helps. Please feel free to ask more questions if you would like or need clarification.

Proper use of state in React

I am new to React and a bit struggling with state in React and how and where we need to use it. So far, I found out that "If modifying a piece of data does not visually change the component, that data shouldn’t go into state". So, state is all about re-rendering the UI(I hope I am correct). So, the question I want to ask is Is it true that we use state only for re-rendering the UI only?, nothing else and nothing more?
You can use state in your class components. State is like private data of your component that may change by action made by user.
State is immutable. This means you can not change state directly in following way this.state.someVal = "smth". The only way to change state is using this.setState() method.
When you change state value React automatically re-renders your component without refreshing the page. In other words React.js reacts to your changes
State is an object that is directly tied to rendering the component. The reason why you can't change State directly with say this.state.foo='bar' is that React would have no way of knowing that it needed to re-render the component if you did that. Thus there is a setState method to change the state, which under the hood calls the render function of your component.
Therefore, if you have some data that has nothing to do with rendering the component, you don't want to put it into state, as setting its value will cause unnecessary renders to occur. If you're using class components, you can just put that data on the class directly: this.foo='bar'.
Basically yes! Two examples might be: A - holding a list of items (shopping list, or todo items) that are rendered directly to the UI, that are subject to change as the user adds and removes items. B - a value that determines whether or not you want something to show up on your UI, for example, you might have a state value called 'showNavbar' that is either true or false, depending on whether you want the user to see a navigation bar.
I hope that helps make sense of it in a basic way :)
We use the state for rendering the UI.
Also, I think the State allows React components to change their output over time in response to user actions, network responses, and anything else, without violating this rule.
For this, We use the 'setState' method.
setState() is the only legitimate way to update state after the initial state setup

top-down rendering - how to solve state in pre-populated input fields

Scenario: I have an react app which has its state in flux store (async load), passing data down to Root component which is passing data to its children and so on.
now: text input field, nested somewhere deep down in node tree, has its initial value done in getInitialState from a prop (the prop has been passed down), and on onChange event its state is set to typed value. So far book example.
Now let's 'submit' the form, action is triggered, ajax call has been made, data came back changed, passed to the store which emits event to Root component, the node tree gets re-rendered again, BUT of course getInitialState is not triggered again, and the field still has the last typed in value.
I don't think I want to initiate the whole action-store-root-children-reRender loop on every single key stroke, right?
Question: How do I get the input's state to be fresh from the passed prop (the store one)
THOUGHT: Hmm, I can actually tell when I'm initiating re-render from the ROOT, by setting a store 'flag' in ROOT's componentWillUpdate() then setting it back in componentDidUpdate() - then all the child components can know if it is ROOT intent to re-render or just a parent non-store initiated change.
Keep the form's values in the store instead, and don't using any local component state at all. When the form is edited trigger actions to update the store and re-render the app.
First of all what you are doing is an antipattern. State should not be set equal to props. Your props should not be state.
The React docs are pretty clear on updating props.
Check out this link: https://facebook.github.io/react/docs/component-specs.html
componentWillReceiveProps(object nextProps)
You should think about implementing this lifecyclemethod it will help you to be aware of prop changes.
But please think about seperating props and state - there is a reason why React Framework has both. But that is a different topic.
EDIT1:
If you want to update your stores state then call a flux action that referes to the corresponding store and pass in the props as payload inside of the lifecyclemethod above.
Hope this helped.

Different actions for common components in FluxJS

In my flux application, I have a DropDown React component that renders itself with an array of Key Value Pairs.
I'd like to have two different drop downs, one with Country Data, and another with City Data.
In the Flux pattern, each dropdown would have a Selection Action that contains a payload of the selected value, which a corresponding store would use to update it's state.
How do I specify which dropdown Selection action belongs to which store?
I can create a wrapper component that is specific to each need i.e. CountryDropDown and CityDropDown, and have each create their own specific action CountrySelected and CitySelected but is that the idiomatic approach? If it is, how do I wire up the underlying DropDown component so that it's onChange handler fires the parent's action?
Actions should not belong exclusively to one store or another. This is very much like creating a setter method in the store, which is antithetical to Flux.
One of the central ideas behind Flux is that all stores are informed by all actions. The dispatcher is the mechanism by which actions are distributed to all the stores. This keeps the flow of data open to changing needs.
There are probably a few different solutions to your problem.
I would consider adding a selectedType field to the action that is either 'city' or 'country' (or you could use constants instead of strings). You could pass this value into the React component as a prop, if you are trying to keep it abstracted.
Likewise, if you would rather have completely flexible control over the behavior of the child, and you want to define that in the parent (your final question above), you can pass a callback to the child component as a prop.
You could have separate actions dedicated to each type, as you described, but that seems like duplicating code to me.

Categories

Resources