Am I thinking in in react correctly about form behaviour - reactjs

I'm debating refactoring parts of a site I'm working on from jQuery into react. Before I start I'd appreciate some feedback on my thought process so far.
<DeviceChooser>
<ManufacturerSelect />
<DeviceSelect />
<ButtonOne />
<ButtonTwo />
<DeviceChooser>
That is the desired component. It's behavior is:
The parent (DeviceChooser) gets some json data via ajax on componentWillMount.
It passes part of that data to ManufacturerSelect, which is a select field.
Once something is selected there, DeviceChooser passes some other data to DeviceSelect, which is also a select field.
Once something is selected there, if some conditions are met, both Button1 and Button2 become active
Clicking Button1 or Button2 would redirect the page to a specified url, with parameters set depending on the 2 select fields.
More practically speaking, you choose your phone manufacturer, then in the next select you choose your device from that manufacturer, then you get redirected to either page1 or page2 with some get parameters depending on the button you press.
My questions are:
Who's responsibility should it be to decide whether the buttons should be active? The DeviceChooser or the Buttons?
Who should compose the redirect URL? The Chooser or the Buttons?
I'm going to have variations of this DeviceChooser component all over the website, what can I do to ensure at least some reusability? The caveat being that sometimes it will have more select fields that just 2, and other times different select fields will be part of the equation depending on state (Like, if your device is a laptop, you also specify what shape of edges the device has)
I'm really grateful to any feedback at all. I've also created a Gist with the code I've come up with so far, if it helps.

One of the methodologies that I have followed since getting invested in React is using containers. Containers essentially are components that are responsible for retrieving and manipulating the data and then passing all the relevant data down to all the child "dumb" components that are simply responsible for rendering said data.
Operating under this premise (or something similar) I would suggest doing calculations in the container on the initial data, and pass everything down.
So in this instance we should be do the following in the container (or parent component)
Get JSON data via componentWillMount
Manipulate the data and pass it to ManufacturerSelect
The other questions depend on which framework you're using. Are you able to elaborate on this? Are you using Redux, Flux, ReFlux etc?
I've had a quick look at your code, one super useful thing that I think you should do is specify PropTypes for each component. This helps immensely for debugging, and when you're talking about reusing components in several distinct locations this will be crucial. Also (without understanding the full context) is it necessary to use state everywhere in your components? Would it be possible for them to simply render the props passed down to them? (again this depends a little on the store you'
re using).

It's a relatively generic question, but my line of thinking (quite opinionated) would be as follows:
Your Buttons should become simple, generic Button components that should for this example have the following props (besides perhaps some styling props):
disabled
title
onClick
Your Device Chooser is the one who's got the awareness that components mix together, that these buttons should actually continue to do something after they're clicked, so you'll want to handle that knowledge solely within that component. It glues the rest together (passes data around) and should therefore also make these decisions.
<DeviceChooser>
<ManufacturerSelect data={this.state.manufacturers} />
<DeviceSelect data={this.state.devices} />
<Button
disabled={this.state.selectedManufacturer === null ? true : false}
title='Manufactuer details'
onClick={this.handleManufacturerDetailsClick.bind(this, this.state.selectedManufactuer}}
/>
<Button
disabled={this.state.selectedDevice === null ? true : false}
title='See device details'
onClick={this.handleDeviceDetailClick.bind(this, this.state.selectedDevice }}
/>
<DeviceChooser>
Device chooser's method than can be something like:
handleDeviceDetailClick(device) {
history.pushState('/device/detail/' + device.id);
}
You want to separate your functional components from the stateless ones. A good read for this is http://tylermcginnis.com/functional-components-vs-stateless-functional-components-vs-stateless-components/

Related

how to develop a screen where this similar/same screen is presented in multiple flows

I am developing a website in React.
In this website I have a screen - lets call it "book-an-appointment"
And I have multiple flows:
book an appointment for existing client
book an appointment for non-existing client
book-an-appointment is part of flow 1 and 2, with slight differences:
some buttons that are shown only in one of them
"next" button that takes the user to a different screen
it affects differently on the funnels
of course each one of them is in a different URL
and more...
Question: Which approach is best practice in developing such screen in react?
options I thought about are:
Creating A single screen that shows the relevant buttons and actions according to the state
Duplicating the screen for each flow (because of the small differences in it)
I am quite new to react. tried to look for an answer here and in google but couldnt find my answer.
In that case I would just use one Parent component with ether two child components with the different flows. You can make one JSON object where conditionally you add specific keys and you can later check if the isExisting field exists for example what kind of booking it is and show a the existing user flow component.
You could do it like that or have one component that just conditionally hides fields depending on what type of booking it is. In this case you would use conditional rendering. See the article below for more info.
https://reactjs.org/docs/conditional-rendering.html#inline-if-with-logical--operator

Toggling between React Components toggling with state vs React Router

I was trying to toggle the page with a buttonLink and list elements when I click on the buttonLink. I can basically see 2 popular possible approaches to this:
Using react router and create routes one for the list button and another for the list elements that opens up when clicking on on list button element which gets list elements as props in router
Pass the props to list element but render it in the same page, but with state toggle condition. Example -
this.state.showList===true ? :
Here I'm confused to decide between these 2 approaches. I preferably chose the 2nd approach to toggle between components based on state as I'm less comfortable with Router. But if the number of components in that page increases, it is difficult to maintain it using state value.
But I would like to know that standard approach for medium scale applications.
Any examples or pointers would be helpful, thanks.
I'm using both approaches and distinguish between encapsulated business logic and modifying logic. For example you have persons and relations between those persons. So I have 2 routes <personId>/details and <personId>/relations. With the first you will see person details like name, address, telephone numbers and with the second you see a network of related persons, who are connected with this person. For me I decide between those 2 approaches by what I expect to see after reloading the page (pressing F5). When I'm on the detail page I want to see the details again and also I want to see the relation network again.
But there are some modifying logics like adding a new a new telephone number. Normally you would do this by showing a modal dialog or expanding a form with some inputs and "OK"/"Cancel". When this dialog is opened and doing a page reload I would expect to see the person details again. So I'm implementing this dialog via {this.state.showAddTelephone && ...}
In my opinion just go with react-router. Routes are used in multiple areas of the app. The logic of conditional rendering can introduce too much complexity if it's being used in a lot of places. It would be easier to just take the declarative approach of the router with no logic behind it.

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.

Better approach to create react-redux layout header component

I'm going to create a large scale application with react and redux and start to build the header component of the layout very first time. The layout header will have 4 child parts.
1. Icon that will show all the online users after clicking on it
2. Icon that will show latest 10 notifications after clicking on it
3. Icon that will show latest 10 messages received after clicking on it
4. Logged in user name that will be dropdown button to show some "My profile, logout, account setting" navigation links.
As I've read about redux at so many places that we must have as less as possible stateful components. So by keeping this concept in mind, I thought to have only one header smart container with a header state consisting default states for all icons like
{headerOnlineUsers:[], headerMessages:[], headerNotifications:[]}.
So if I follow the redux best practice and create only one smart header container with 4 different dumb components, the each and every time the state of any of them is changed, the whole header container will get re-rendered.
But I want to re-render only the state changed component.
For example, If I get a user joining the chat through websocket, It will dispatch an action and the reducer will update the headerOnlineUsers list of the state. But In this case I want my only online users component to be re-render not the whole header container.
Can anybody please suggest me the best approach to implement this kind of layout.
I would not go for your option, but would prefer a more granular approach.
What if you split the header in 2 later on, or want to display the button somewhere else ?
What if you have another version of your header for a subsection of the website ? You would need another container that gather again all the info.
The logic in general in redux is to separate what is data-sensitive and what is not. Your individual lists are data sensitive, the header in itself has no reason to be so far. What's more, if you want to attach actions to the icons it will quickly become messy to bring back thoses actions to the header and then its container, and even messier if you ever need to move them.
The way I would do it (and the way I do it right now as I halso develop quite huge app with react and redux), would be to have a store with those 3 lists of items, and then 3 containers, one for each icon/dropdown that links one aprticular list to the component.
Then the header is just a stateless function holding all the containers together. This way if you ever need to move one button somewhere else or reuse it, you just import the container and voila!
React.js will take care of only re-rendering what is required. So this problem is already solved for you :-)
What you plan to do sounds sane to me, I just would change one bit: The smart header container should not use internal state. Instead, your redux store should look like this:
{headerOnlineUsers:[], headerMessages:[], headerNotifications:[]}
and you should pass the redux store into the smart header container (have a look at the connect function in the redux documentation). This way, you can use the redux store contents in your component via this.props, and that's it.

Inserting text into input in descendant component with React

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.

Resources