I had a problem with tab rendering. The contents of the tabs used to get mixed up as i used the same component on all the tabs and the component had sub-components with id. As the id would appear same on all panels, the components used to get mixed up. I am now using itemId instead of id and the tabs are getting rendered properly.
Now I am facing another problem. Initially I used Ext.getCmp(id) to fetch components in the controller. Now that ids are replaced by itemId, I am using the following:
Ext.getCmp(id).getComponent(itemId);
There is a deep nesting of components in the view and all the intermediate components have itemId. With the above statement, as I go on to fetch deeper components, the statements keeps extending like:
Ext.getCmp(id).getComponent(itemId1).getComponent(itemId2).getComponent(....;
Am I using the statement correctly? Is there a better shorthand method to achieve the purpose?
Please advice.
Basically you using it the right way because a itemId is only unique at component level (at least it has to). But as you might see this will get sort of ugly, therefore I strictly recommend you to use Ext.ComponentQuery or one of it's implementations up() and down() which are both available for most components. Where Ext.ComponentQuery will per default look through the all instantiated components up() and down() will start at the component from which they are executed, only walking through the existing component tree. Also up() and down() always returns the first match where Ext.ComponentQuery always present you a array.
Both accepting the same query string which can be written in various ways (here I recommend you to read the docs)
Here is a example for:
Ext.getCmp(íd).getComponent(itemId1).getComponent(itemId2)
expecting that you are using panels (it can be any component)
Ext.ComponentQuery.query('panel[id=yourId]>panel[itemId=yourId]>panel[itemId=yourId]');
lets say you are using MVC and therefore all your components are custom (have own xtypes). So if you know, that you have only one instance of 'yourcustompanel' with this itemId you may the simply call:
Ext.ComponentQuery.query('yourcustompanel[itemId=yourId]') // note you get always a array
You can use the Ext.ComponentQuery.query(..) or down() or up() to get the component you are referring to.
If you want to get a component(say a button) within a certain component(say within a container) ,you can use
var button = Ext.ComponentQuery.query('button[type=messageButton]', this);
In the above 'this' refers to the container scope.
Or you can use
var button = this.query('button[type=messageButton]');
In the above also 'this' refers to the container scope.
Hope this helps you ..
Related
I've been reading about the advantages of using Context in React and I am unconvinced. I'm wondering if there's something I've missed.
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
What's the hassle in creating a props object in the main component and just passing it around among the underlings? Something like:
// do this once at top level (I'm assuming [foo, foo_set] and [bar, bar_set] are state variables):
const props = {foo, foo_set, bar, bar_set, thisAndThat, theOther, whatever, etcAndEtc}
// including one component
<MyComponent1 {...props } />
// including another
<MyComponent2 {...props } />
(Maybe better to use another name than props for this object, as the components can have other properties. Anyway.)
Then in MyComponent1 you can access all the props you want, or not access them. Either:
...
const MyComponent1 = (props) => {
...
// here we can use any props we need, props.bar, props.bar_set, props.theOther for example
const localVar = props.bar * 2;
props.bar_set(localVar);
// this changes the value of bar throughout the app
...
}
the advantage of the above, as I see it, is that you can pass around the props object to other sub-sub-components and not worry about whether you have anything missing.
Or:
...
const MyComponent1 = ({bar, bar_set, theOther }) => {
...
// here we can use bar, bar_set, theOther in the same example
const localVar = bar * 2;
bar_set(localVar);
...
}
The advantage of this option being that the syntax is shorter.
So my point is why not just use the standard JavaScript syntax? Why introduce new concepts when there are plenty to assimilate to do all sorts of other things?
Consider a fairly common case for most applications: You have authentication information (eg, the current user), a routing library (eg, react-router), and a theme object (what colors to use). These are needed in components scattered throughout the app.
You want to render a button somewhere down at the tip of the component tree. It's going to show the user's avatar, so it needs the authentication data. It's going to navigate when clicked, so it needs the navigate function from the routing library. And it needs to style itself according to the theme.
This certainly can be done through props, but in order for the button to get the props, every component in the chain above it must get and forward those props too. This could be many components deep, like page component -> section component -> table -> row -> widget -> button, and most of them don't need that information for themselves, so they're just taking the props in order to forward it along.
And you can easily imagine cases where there are more than 3 pieces of data that are needed across the app.
What's the hassle
Most people find this "prop drilling" to be a hassle, but let's assume you don't. You still have the problem that it has bad performance. If every component must receive the full set of "global" values that the app might need, then any time anything changes, the entire app must rerender. Optimizations like react.memo become effectively useless. You will get much better performance if you only pass the props you need.
Easier to edit code (You don't have to delete for example unused variable)
Better redability (You dont see unnescesary variables, and You see which component is using variables)
Lesser performance waste (preventing from consuming unnescesarry variables)
Suppose You got 10 descendants in - You would have to pass one variable through 10 of components.
What if some could have the same variable name ? You would have to edit Your passed variable for a while, then edit back later.
To sum up:
Using Context more efficient than stuffing everything into a single object variable, because it avoids re-rendering the whole app when anything changes.
People think passing a single variable around is more hassle than introducing specific syntax.
Context also allows you to have different values for the same variable in different parts of the app. This is shown here (the best explanation IMHO) : https://beta.reactjs.org/learn/passing-data-deeply-with-context
The above article also specifies that sometimes passing props is the best solution. It gives a list of use cases for context, and the advantages provided in each case.
I'm trying to make a scene graph in React that supports nesting components. Something along the lines of:
<SceneNode>
<SceneNode>
<Thing/>
</SceneNode>
<SceneNode>
<Thing/>
</SceneNode>
</SceneNode>
When a SceneNode is mounted I need a way for it to know at what "depth" it is. Is there a way within a component to access that information? e.g.:
function SceneNode({children}:{children:ReactNode}) {
const depth = useCallDepth(); // <- some magic function that lets me know the level of nesting for this node
return <div>{children}</div>
}
NOTE: I've tried the following:
Context: Can't get it to work without having each node create its own context but since context is referenced statically in React I can't access the dynamically created parent contexts from children.
Refs: The nesting of components should be reflected in the DOM elements they produce, but I can't figure out how to determine what the associated component is for a given DOM element - i.e. is this div a SceneNode or just a random div? (I suppose I could encode it in an attribute or id, but I was hoping for something a little cleaner and less invasive)
Manual: I can manually specify which nodes are parents (e.g. <SceneNode parent={true}/> but that's pretty error prone.
It is possible to use context for this: Demo
I do want to create a React component tree in memory (not in the DOM) with the same behavior a React Portal has, that is, it should use contexts from the parent component tree.
So is it possible to create something like Portal but instead of render it on a DOM node, "render" it in memory (outside the DOM)?
Note that what I need is the component life-cycle of some components in the tree while the visual part will be hidden, but in my case if I put the component tree in the DOM within a hidden div the performance is not good and then I want to test a different approach.
Two possibilities come to my mind:
1) create a portal to a DocumentFragment
When you use ReactDOM.createPortal, you could point it to a documentFragment in memory rather than an element on the page. The nodes that get created should then be appended to that fragment in memory. Whether or not this meets your criteria or not i'm not sure, but it would look something like this:
class Example extends Component {
constructor (props) {
super(props);
this.fragment = document.createDocumentFragment();
}
render() {
return ReactDOM.createPortal(
this.children,
this.fragment
);
}
}
2) Create a custom reconciler.
If you want the data to be output in some particular format instead of being DOM nodes, you could create a custom reconciler. This is non-trivial thing to do and uses the react-reconciler package, which the react team describes as "experimental", but it would give you very precise control of what to do with the results of the render.
If this is something you want to do you can read some at the react-reconciler readme, and it may be useful to look at the configuration files that are used for other reconcilers (see the "host config" links near the bottom of the readme)
I have a table component that displays at table, and a print component that displays the same table in a format ready for printing. Both reside in the same HTML page.
The print component needs some information from the table component. This information is useless to the outside controller, it just needs to get from one component to the other.
The obvious solution was to output-bind a printInfo object to the table component, and input-bind it to the print component, like so:
<table-component ... on-print-info-changed="vm.onPrintInfoChanged(info)"/>
<print-component print-info="vm.printInfo"/>
I set printInfo in onPrintInfoChanged.
while this works, it doesn't seem right. Since both components already rely on each other, I'd much rather do something like this:
<table-component .../>
<print-component table="<ref to table-component>"/>
That way the controllers doesn't need to know anything about the dependency between the two components, except that there is one.
The question is - how do I supply the reference to the table component? I can get the table controller's element on the page, but how do I get the component's controller from it?
I found some old (and sometimes contradicting) answers, but they were all relevant to old versions of Angular, before anybody used components or ES 6.
I have a table and I'm deleting a row. When I delete this row, I want to reload the current Backbone route, but few things to take in count:
e.g I'm in this route
"oneurl#order-by-name/page-8"
If the table, at that page, has only one record and I delete it, I would like to redirect to #order-by-name/page-7, so I need to get the "page" parameter. If there are still records, I want to "reload" the same route (to add next page's row if there are). It seems is not possible (https://github.com/jashkenas/backbone/issues/1214).
Any ideas?
As discussed in the issue you link (mainly jashkenas's comment "trigger: true is usually a code smell"), you shouldn't really be using routes like that for a javascript application.
What you should be doing instead:
have somewhere to store the current application's state (e.g. a plain javascript object) which is passed to the function taking care of displaying the views and data you want
when a row is deleted, modify the application state object (e.g. changing the current page attribute) and call the same function as above, once again passing in the configuration
update the url with navigateonly if the fragment should change
In reverse, your router should parse the url fragment to generate a configuration object discussed above, and call the function to render the views (passing in the configuration info).
For more on how to manage routing without using trigger: true everywhere, take a look at http://lostechies.com/derickbailey/2011/08/03/stop-using-backbone-as-if-it-were-a-stateless-web-server/ and the free preview to my book (on Marionette, but the same applies to Backbone) which also contains a chapter discussing route handling.