Inserting text into input in descendant component with React - reactjs

I'm diving into react for the first time but I'm having some difficulty with a particular requirement. I have the following component structure:
Survey
--QuickTextOptions
----QuickTextOption
--Question
----Answer
------TextAnswer
As you probably can tell, I'm working on a survey application. A survey author would create a question, then answers (i.e. sub questions or options). There will be a number of different answer types including checkbox and text.
Also at the top of the survey, above the questions, are a list of "quick text" options. When one of these is selected, some text is appended to the value field of the appropriate TextAnswer's input field. A user can select as many of these as they'd like.
This is trivial to do with just javascript, but I can't figure out a good way to do this with React without adding refs to components down the chain of the survey.
If I pass it in as a prop, have AnswerText as a controlled component, and set value={this.state.value + this.props.quickText}. It just re-inserts the text on the handleChange event of AnswerText.
I'm considering using refs and calling child functions from parents but refs seem to be discouraged and I'll have to do this for Question, Answer, and AnswerText in order to pass it down the chain which seems a bit too much.
Is there any other way to fire an event to a descendant down the chain with some data? It's a one time addition so props seem to not work well for this.

Do you use something like FLUX and global state? In my practice, usually you build such app working around global state which stores your input data. This way you can edit it transparently from different places according to action events (the only ones which can modify that input value, inputs themselves are not doing that).
So I see that it should look like this:
You pass references to global state object deep into your components and to your form's input.
When you start typing each new character triggers event to modify global state value for this input. You're getting updated value instantly in your component's props and component renders newly entered character.
When you want to modify input from some other component (by pressing button) you do almost the same. You click on button and it triggers event saying that global state value for that input should have "some string" added. Your input component receives callback with new props and renders this text instantly.
By saying event I mean special event which gets some value and inserts it into global state. Rest is done by framework.
Hope this will help you to design your app. The approach I described above is a short description of how Tictail Talk web chat client works now.

Related

React - Dividing a Large Form into Multiple Components

I have a large form consisting of 30-40 fields.
The form is logically and visually divided into parts. For example: "address details" "credit card details". I would like to divide it into multiple React components.
In my form, changes by user in some parts often cause other parts to change. Some changes are:
Resetting certain parts of the form.
Auto-filling certain parts of the form (e.g. for certain credit card we automatically offer address saved from past transactions)
rerun validity check of different parts (e.g. we only ship to this address for purchases of 100$ or more)
As far as I understand in React parent should not call functions on children (through ref) but rather declare state, which flows to the children through props. However, all of the changes mentioned are just initial state, and can be immediately overridden by user input.
My options as far as I understand are:
imperatively pass state to children. This could be done through ref, or through a prop "initial/override value". Either way I'm manually passing state, rather than having one single source of truth.
Make my children forms "dumb" and receive all form values from parent. This seems impractical (as far as I can tell) because I would have to pass every single input value up and receive all of them as props.
Similar to 2, store the state in Redux. I would still have to store every single value of the form in the store, which is cumbersome It also seems to be discouraged by the React community.
Give up on dividing the form into sub-components. I only have one source of truth (component state) Honestly that currently seems like the best solution.
How would you do it?
Thanks for your time.

Initialize state from props using rehydrated Redux store

In my application I have a dialog window on which there are multiple input fields. What I want to do is to save user's input in the component's own state and only afterwards, say, inside "onClose" of the Dialog send the input to a redux store using "dispatch" function.
This way the dialog component would keep field data inside its own state.
The problem that I face is that I'm not sure what the best way is to rebuild dialog component state from information contained in the redux store.
If one refreshes the page with F5 or simply reloads it, then components lose their state and fields will appear blank, regardless of the fact that rehydrated redux store still contains valid input information.
The question is then, what is the best way to set components state from props? Moreover, doesn't it seem like an antipattern? What are some common techniques for such task?
One possibility is to set field values directly to those contained in "props". This would, however, imply that every small change of the input fields will result in copying and modifying redux store, which is slow & inefficient.
Usually building a state from props complicates code a lot, you have to map props both in constructor and getDerivedStatesFromProps.
I prefer to write component functions which return value based on passed props.
As you mentioned it may impact perfomance, to fix it you can use memoize-one library.
For more details you can check the following answer

React nested Component, arbitrary communication

There are many answers regarding react component communication, but seems none of them resolved my problem. Here is my problem's detail. Please help! Thanks in advance.
I'm building a flexible form. The UI is generated by nesting components.
The form data structure could also be nested json objects.
i.e form can have some inputs and sections, sections can have some inputs or sections, and go on.
sections is just UI layout components, doesn't care about data or state.
But input (could be text input, checkbox etc anything to capture data)
The problem I'm facing is any input's validation could depends on any other inputs' value.
i.e inputA has validation expression like formData.inputB >formData.inputA + formData.inputC
But they could also have no dependency at all if you don't give a validation expression.
If I pass the whole formData down the component tree, every time I type in one input, the whole form will rerender.
I have considered redux, but real not sure how redux can help such case. I'm still relative new to react and redux, so I could be wrong.
So what could be a viable solution?
Its a common issue when you're modularizing form elements. I have the same problem.
Redux is by far the most controlled solution. All of the components can listen and update the same object simultaneously. But you can also attach functions as props from the parent that you bind to the parent. The function would fetch the state of the parent and update the state like a makeshift store. If you're a good developer, this is possible but neither are simple to do. Good time to learn :)
There are various solutions to your problem, but in general it shouldn't even be a problem, because rendering (even of large forms) should be quite effective with React.
The core tool for adjusting performance in React is the shouldComponentUpdate method of your component classes. If you're smart about what you pass to the individual form fields and then implement shouldComponentUpdate properly on them, you should be able to update only when needed. In your particular example, you don't need to pass the full object everywhere.
You can just pass value, onChange and isInvalid to each field and calculate the validity at the root (where you have access to the full state). Then the shouldComponentUpdate of your fields can decide just based on those props. (Obviously this is a simplistic example, but as a principle it's sound.)
Sure, Redux is another possible solution. If you keep the state in Redux store and only connect each of your fields to the portion of the state it needs, you should be all set. It brings quite a change in architecture though, so you should choose Redux only if you really want it for your app as a whole.

Correct way to update owner state

I have two components, contact form, and input.
At this moment i pass onChangeEvent from contact to input as is described in many tutorials and its works fine - input update his owner state.
But there is way to pass 'this' from contact to input by prop, or context and then I can update owner state without passing onChangeEvent - but is this a good idea?
Is there another option to update owner state without passing onChangeEvent?
I believe you could technically do it, as a React component is a regular javascript object in the end, so you could pass it as a prop.
However, that's not a good idea in general, for various reasons:
It tightly couples the two components together. If you ever want to reuse the input component in another place, you'll need to pass in the exact same state.
Linked to this, it allows manipulation of the internal state of one component, by another component, which is a violation of good OO design.
You are right however, that things tend to become quite verbose when working like this. They also become hard to reason about when one has more complex trees of components passing props and change handlers between them.
One solution to the problem, is employing the Flux design pattern, and namely it's Redux implementation.
In Redux one has a single piece of global state, a plain object, of which components see pieces (sub objects). Components receive this state as props, and just render from it in a simple fashion. There's a set of actions which transform this state, and any component can issue such an action, as a result of user interaction. There's still the concept of "state", but it is reserved for truly local things, such as the state of a form before pressing the save button etc.

Calculating data dependent on non-committed (state) data of child/distant components in React

TL;DR edit in retrospect years later: there's no solution that's not gross as long as it's just state data - you'll need to also get it into a separate store somewhere somehow and can do whatever you want at that point. But read the question and the answer and the back-and-forth if you want some more background.
I have a table of two sections, each with various input values. Let's say that it is a survey. Feeding data into this is straightforward; I have the typical model:
{ "sections": [ { "name": "a", values: { "A": 1, "B": 2, "C": 1, ... } }, ... ], ... }
And a component hierarchy like:
<Survey>
<Section> (for each section)
<ValueRow> (for each value)
I put the model into a prop on the survey and the right information is trickled down into the subcomponents. Each ValueRow has a text field and its ephemeral value reflected back into its own state. This works fine "on the way down", in the one way flow that React is built for.
However, I also wish to show progress on the Section level and for the entire Survey, both simple things like number of fields filled out and statistical data needing the entire data set - what's the average across sections, how many "1" answers do I have in total, what's my grade (calculated from all the answers) and so on. Essentially, I'd also want to have:
<Survey>
<SurveyWideStats>
<Section> (for each section)
<SectionWideStats>
<ValueRow> (for each value)
This turns into a reduction of the current state instead of the model data. What's the best way of doing this in React? Flux and Actions and Stores all seem to deal with how to handle the data once it has been committed to the model. What I want to do is to pluck all the state data and do something with it, but it also seems terribly gross for the SurveyWideStats element, for example, to go poking through the garbagestate of its sibling element's children.
My current solution is to pass around an accumulation object and provide enough state to each component that it can keep calling that whenever something changes. This seems clear and divided enough, but it means that I have to have two passes and have to be careful not to start fiddling with state during rendering (at least since that's when I call the accumulation object - I suppose there may be a better point during the lifecycle where I could call that). And in addition, it seems like this would be an obstacle to "pick up from" server side rendering.
What's the best way? Is there an established pattern for this - preferably one where these things don't have to be so custom and really tailored to the data all the time?
Two ways to do this:
Pass the entire table as a prop to the highest component .
Inside survey's render function, calculate the stats, then pass them to the component as props, followed by the foreach loops over the table for the other children components. That way, your stats component is a pure component, does not need state and does not need to poke in siblings.
Create a stats function in a store, and have the component call this to get the stats. NB best not to save the stats in a store, since it is clearly derived data. Unless for performance reasons.
Hope this helps!
UPDATE:
To handle changes by the user when they change an input value, you have two options, depending on your preference:
(Option 1 describes a pure component).
(When you use flux pattern): Put the value of the input control in props. And whenever the user makes a change, fire an action to update a store, and have the store pass down updated props. So the (top) component notices a change event and rerenders. This creates more or less 'live' updates, e.g. when a user types a single character in an input field, the page title is updated immediately. The component with the input control does not have (and does not need) setState. This setup may become slow in really large component trees (because with each character, the entire tree is rerendered). But react is superfast and smartly only renders changes in de tree.
Put the initial prop value in state (in getInitialState() and put the input value in state also. Typical example: user types a character in an input field, the change triggers a setState() and the component is rendered again. Only when the user clicks some save or commit button, an action is fired to save the value in a store.
UPDATE:
As a bonus, below the flow for updating stores and components.

Resources