There are other similar questions that have been "answered", but the answers aren't complete and they don't solve the real problem.
This is really a two-parter with a sub-question.
1. What are the general situations you would want to use this.props.children?
2. What are some specific situations with examples?
I have read the docs, please don't only quote the docs.
Motivation for this quesiton:
The reason I for this question is that at the time of this question, the docs give a very very general example of how to use it and the methods to use when doing this, but the example don't give us true context. It isn't usable IRL. The example could be literally reused all over an app without rhyme, reason, or regards to sanity. Is that really ok?
I have been told you will use this.props.children, "when you don't know what children will be passed." But technically you never really know what changes may come down the line that require more or different children. So this is pretty ambiguous.
Also I found an interesting article by Jake Trent: http://jaketrent.com/post/send-props-to-children-react/
The article shows how you can add/remove props being passed to these "unknown children" based on the type of the component, which is neat(and possibly a good idea when you build a third party component).
My big takeaway so far is that you are giving power over the children to the parent, when you specify this.props.children Is this a good reason or just a byproduct? (example: proptypes, actual typechecking ... ) but,
2a. What other things would/could/should you do here?
2b. What things should you not do?
Examples please!
I like to think of components that make use of props.children as general wrappers, like most other HTML elements.
Think about the fieldset element.
<form action="/post">
<input type="text" name="myValue" placeholder="Some Data" />
<input type="submit" value="Submit!" />
</form>
What a pretty form we have made! But I want it to look...different. I want it to kind of look more visually like a form. Like I want some borders around it, maybe a little label in the top to describe it...Ahh I'll wrap it in a fieldset!
<fieldset>
<legend>A Pretty Form</legend>
<form action="/post">
<input type="text" name="myValue" placeholder="Some Data" />
<input type="submit" value="Submit!" />
</form>
</fieldset>
Now it looks just how I want! Sprinkled in a little legend too, to make this example...legendary.
The point is though, fieldset provides a reusable component with certain attributes that can be used to group HTML content. It's child elements are absolutely irrelevant to it's functionality.
Could we use the same principle in React? Yes. And it can be much more powerful!
Let's say we want to have a special ReactFieldset component, based on an HTML fieldset, that has it's own functionality. I'm not going to code that all out, because who has the time? But imagine you made a ReactFieldset component with a bunch of it's own functionality: it can collapse, it can move, it can do all kinds of things! And it can also hold any kind of content.
Well, then all you need to do in it's render function is:
render() {
return <fieldset { ...superFunctionalityControllingProps }>
{ this.props.children }
</fieldset>
}
Tada! You now have a reusable component that has it's own functionality, and can hold any children.
So the point is: this.props.children can be used when the children aren't really that important at all! The emphasis can actually just be on the component itself, whereas the children are arbitrary components it just happens to house. They needn't even be functionality related at all.
This is used a lot in React Native. Many different components have their own functionality, but can house any children, because they are just "wrapper" building blocks.
Related
I'm often in doubt when I want a new behaviour of a component.
Let's make a simple example, I have <app-title> component:
<div>
<h1>{{title}}</h1>
</div>
Some time after, inside another page I need to put a button alongside the title. The problem is, should I create a new title component or should I parametrize the existing one?
I can edit <app-title> to look like this:
export class AppTitleComponent implements OnInit {
#Input() showButton: boolean;
title = 'App title';
constructor() {}
ngOnInit() {}
}
<div>
<h1>{{title}}</h1>
<button *ngIf="showButton">{{buttonTitle}}</button>
</div>
This is a simple example and may be obvious but using Angular I always have this problem, think about complex components: the #Input() would become many using this method, but creating a new component would increase files and complexity.
From this example you could say to create two components, one for title and another for button but that's only because this is a very simple case. Think about changing a component from "compact" mode to "expanded" and viceversa. On the one hand you may need to have the large component and on the other hand have it smaller in size and showing less information
Is there some guideline about this?
Thanks
I think it's important thinking about behavior within the context of your component. Is the button core to behavior of the title component? Does it make sense to not only display the button, but also handle its events within the context of the title component? If the answer is no, then at some granular level I'd split the components.
Here are some other things you can consider:
Anticipating that your title component may need some content wrapped with the title, you can use transclusion:
<div>
<h1>{{title}}</h1>
<ng-content></ng-content>
</div>
Then, in the parent, you'd do something like this:
<div>
<app-title-component title='title'>
<button>Some Button Text</button>
</app-title-component>
</div>
You could write a wrapper component that packages the title and the button together... ie:
<div>
<app-title-component></app-title-component>
<button>Some Button Text</button>
</div>
You could, as suggested, parameterize the configuration. I recommend thinking about if the behavior that you are parameterizing is part of the core behavior of the component. For example, if you want to paramaterize whether or not a legend shows on a chart, that makes sense because the legend is a core feature of the chart. But I probably wouldn't parameterize whether or not the chart should be followed by a raw data sheet. Instead I would create a new component for that and render them in sequence, because the data sheet is not part of the core behavior of the chart, even though sometimes I'd want to put them next to each other.
At the end of the day, you have to think about the decision in terms of your app, your app's future usability, and developer ease (e.g.- will it make sense to a future developer that this button is packaged with title).
I hope you find this helpful.
I keep reading that when in doubt I should turn an element into a component. So are there actually any benefits to turning form elements such as <input /> to components.
Consider the following:
const SomeComp = (props) => {
return (
<form className='someClass' onSubmit={props.handleSubmit}>
<Input
className='someClass'
type='text'
id='someId'
placeholder='Enter Something'
onChange={props.handleChange}
value={props.side}
/>
</form>
)
}
Unless I'm using options like autoCorrect, autoCapitalize, spellCheck the only things I'll save by wrapping the input into a component like <TextInput/> and importing it to various forms is not adding the type prop to each input and maybe the fact that the error for the input is not declared at the top of the form.
Is there anything else I'm missing? What's the most beneficial way to approch such form elements and why?
Usually you will not want to turn very simple elements like inputs into separate components, unless you are expecting some special functionality from them.
The simplest way to go through is to always have, for each functional need (like a login page for example), a smart component for handling the behavior and functionality, and one dumb components for displaying the ui elements.
When you start feeling there is too much code in some of your smart components, or a dumb component has gone to large you can start dividing them. Otherwise try to keep it simple.
I use styled-components and do stuff like this all the time. The basic idea with Styled Components is that you attached CSS styles to your component instead of creating CSS classes to target, for example, all input elements or using inline styles which limit what you can do (i.e. media queries, psuedo-selectors, etc). And it allows you to separate your components functionality from it's presentation (within the same file).
Here is a link to a youtube video on the topic: https://www.youtube.com/watch?v=jaqDA7Btm3c
This way, you avoid the need for a global CSS file that is hard to maintain and doesn't exactly fit well within the webpack ecosystem that views your assets as a graph of dependencies.
If you are not interested in styled-components, and are happy with the way you style your form elements, then I see no reason to create a custom Input component.
For example, in Facebook's docs on React forms, they do not create custom form components.
https://facebook.github.io/react/docs/forms.html
Unrelated:
If you don't already know, you can write your example like so:
const SomeComp = props =>
<form className='someClass' onSubmit={props.handleSubmit}>
<Input
className='someClass'
type='text'
id='someId'
placeholder='Enter Something'
onChange={props.handleChange}
value={props.side}
/>
</form>
(removed the () around the single argument, and removed the {} and return statement. Like I said, unrelated, but thought I would mention it in case you were not aware.
Might be a silly question but I couldn't figure the solution out myself or google it. I'm using a button for click+upload files. However, I also want to add the drag+drop functionality the same time - using preferably the same flow object and function. Here's my current code:
<div flow-init flow-name="uploader.flow" flow-files-submitted="uploadFiles()"
flow-file-success="fileUploaded()">
<label for="file-upload" class="upload">Files</label>
<input id="file-upload" type="file" flow-btn>
So I'd like to use the 'uploader.flow' scope for my drag and drop too executing 'uploadFiles()' with it on submit. Here's what I've been trying:
<div flow-init flow-object="...??..." flow-drop
flow-files-submitted="uploadFiles()" flow-file-success="fileUploaded()" ></div>
I believe myself the issue is only that I can't figure out what to put in flow-object. But I doubt it was that simple. Might be something also with the new init? Should it be done or not.
Another way around of course could be to find the first shared parent element and init it there instead for both the same time? But would this be a bit too vague?
So in the end I did what I didn't originally want to do. I went up the parent elements until I found a common one the both were children of and did the initialization for ng-flow there instead.
It works.
I've got an form with the ability to have an infinite number of user-added inputs.
As an example, imagine a job application with an "add references" section. There's a "+" button, as well as an "Remove" next to any already added reference.
Here's an example template
<script type="text/template" id="referenceTmpl">
<div>
<h2>Reference No. <%= index %></h2><a id="removeRef<%= index %>">Remove</a>
Name: <input type="text" name="references[<%= index %>].name" />
Email: <input type="text" name="references[<%= index %>].email" />
(...)
</div>
</script>
When any "reference" is removed, I'd like to renumber the others. As the form inputs may already contain unsaved data, I need to do so without fully re-rendering the template. I'd like to do this in a salable way (one that doesn't require too much extra code per input) as the solution may be used in a more complex application.
Feel free to assume I'm using jQuery if the solution could benefit from it.
Any ideas?
The best way to do this kind of thing without hacking into the code, is to use a model(list) for your so called "references".
You should try Backbone.js in combination with Underscore.js:
Backbone.js documentation
There is an TODO example application that does exactly what you want:
Application code-breakdown
Example application
It might take some time to set up, but when you are finished, you will get work done much quicker.
So the old JavaScript aficionado and the young jQuery wizard in me are having a little disagreement. Sorry for the long setup, but the heart of the issue is whether to embed onClick code directly in my HTML or to go jQuery-style and and use bind() or click(). I find myself & myself disagreeing on this topic quite often, so I thought I would try generate some discussion on the issue. To explain the issue, the pattern below seems to bring this to the forefront most often.
Typical Example
I'm writing a search for a member directory. On my interface I have various filter criteria like "gender", "member since", and "has profile photo". A criteria looks like this ...
A user can select an option by clicking on the text (e.g. "Female") or choosing the radio button.
When a selection is made the appropriate radio button is selected the text is bold-ed
My html ends up looking something like ...
<div id="FilterContainer_GenderDIV">
<span id="FilterLabel_Gender">Gender:</span>
<span id="FilterSelection_Gender">Any</span>
<span id="FilterChicklet_Gender" class="sprite_MediumArrowDown inline" ></span>
<div id="FilterOptions_GenderDIV">
<input type="radio" id="GenderID" name="GenderID" value="1"/> <a href="" id="FilterOptionLink_CoupleGender_1" >Male</a><br />
<input type="radio" id="GenderID" name="GenderID" value="2"/> <a href="" id="FilterOptionLink_CoupleGender_2" >Female</a><br />
<input type="radio" id="GenderID" name="GenderID" value="0" checked="checked"/> <a href="" id="FilterOptionLink_CoupleGender_0" class="SearchSelectedChoice" >Any</a><br />
</div>
The issue really arises when a user clicks on the text link. At that point I need to know which radio set to change,which link text to bold, and take the newly selected text and change my header label. I see a few options for making this type of scenario work.
Options for making it work
jQuery Injection with Clever element names
I can use jQuery to bind to my elements in a generic fashion. $('#FinderBodyDIV input:radio').click(SearchOption_Click); Then sort out the appropriate ID & text with clever dom inspection. For example, name my hyperlink could be named GenderID_Link_1 where 1 is the ID I should select and GenderID tells me which radio set to change. I could use a combination of '.parents().find()and.siblings()` to find the radio next door and set it with the ID.
This is good because my binding code is simple and my jQuery is separated from my HTML
It's bad because my code functioning now really depends on a brittle HTML structure & naming.
Bind elements individually with eventData
An alternate option is to gather up my set of elements and for each individual element do a 'bind()' passing eventData.
var elements = $('#FinderBodyDIV input:radio');
elements.each ( FunctionWithLogicToBindPassingEventData );
This is satisfying because I've separate the logic for binding event data from a brittle HTML structure.
It's bad because I've simply moved the brittle piece to a new function
It's also bad because I've introduced slowed down (relatively) the binding (more DOM traversal).
Embed onClick code in the HTML
This is where my old JavaScript inclinations keep taking me. Instead of using jQuery to inject bindings, I change my link/radio button HTML to include click handlers. Something like ...
<input type="radio" id="GenderID" name="GenderID" value="1" onClick="SetGender(1,'Male')"/> Male<br />
This is satisfying because i know the values when I'm generating the HTML, so I've simplified my life.
I've removed a lot of dependency on my HTML structure (although not all).
On the down side, I've co-mingled my JS and HTML.
It feels dirty.
So what's a boy to do?
This seems like a fairly common scenario. I find it pops up in quite a few situations besides the one I've described above. I've searched tubes on the interweb, blogumentation, and technical articles on twitter. Yet, I don't see anyone talking about this issue. Maybe I just don't know how to phrase the issue. Whatever the reason, I don't feel good about any of the solutions I've come up with.
It really comes down to how do I associate a clicked element with it's related data--JSON, embedded in HTML names, or otherwise. So what's your take?
The pat answer is that embedding the onClick call in the input element goes against the unobtrusive javascript concept. However, I'm the kind of developer that'll go ahead and use it anyway if it gets the jorb done and the audience is not likely to have javascript disabled.
If I'm understanding the problem correctly, you need a way to do things jQuery-style without relying on html structure and such. Give your radio buttons a class name, for example, the "Male" radio button can have class="Male", and you can select it via jQuery easier.
Bonus: There are some instances where you may need to assign some element more than one class, for example, you are filtering by language and by country. So you can assign some element multiple classes like this:
$('#someElement').addClass('French').addClass('fr-FR');
And select it using either class later.