I'm new to reactJS and want to know if what I am doing is in good style and makes sense.
We have a pretty old app that is written in PHP and uses smarty templates/a mess of jquery for front-end rendering. We have recently started implementing react.js and I'm working on a feature where users can view a list of incomplete candidates. This list depends on a site and a test.
A php script is getting called with requests for site and test. There are functions in this php script that then return an array of the incomplete candidates that a smarty template renders.
Right now I have refactored so in the smarty template there is a div where I've implemented a jsx script tag that contains a panel with a list of incomplete candidates.
My question is two fold:
Does it make sense to use "site" and "test" as state and then use some kind of AJAX script to get the array of incomplete candidates or is it in better style to simple set the array of incomplete candidates as state.
How can I set this initial state without the use of Ajax? (Is there say a way I pass state directly from PHP to my react.js components or pass a variable from smarty to react.js.
Regarding my first question I think I need a better grasp on state but from my understanding and from what I've read here: If a Component needs to alter one of its attributes at some point in time, that attribute should be part of its state, otherwise it should just be a prop for that Component.
From my point of view this state is the visit and test and it determines what users should be listed.
I would love some input on if my thinking is flawed. I am still wrapping my head around react.
Cheers.
Does it make sense to use "site" and "test" as state
They should be state if they change at runtime and this component should logically own them (no parent component cares about their current value, or there is no parent component).
They should be instance properties if this component is the logical owner and they don't affect render.
Otherwise: props.
and then use some kind of AJAX script to get the array of incomplete candidates or is it in better style to simple set the array of incomplete candidates as state
If you need to fetch new data based on changing parameters, ajax is the way to do it. I'm not sure what the question here is, because you say "... or is it in better style to ..." but you'd d the ajax, and then put the result in state.
How can I set this initial state without the use of Ajax?
You put it in a global variable (json in a script tag), or a data-foo attribute of an element, and the JS reads that and uses it in getInitialState.
where I've implemented a jsx script tag
If you're using JSXTransformer on the client, it has to load a bunch of code which then searches for script tags, tokenizes and parses the scripts to an AST, performs some transformations on the code, generates a string from the modified AST, and then executes it.
It's a good development tool, but isn't intended for production. The alternatives are not using JSX, or compiling it to plain JS ahead of time and having php send that.
Related
My situation is that I have multiple SVG templates that have data binding on my Angular project, and I want to somehow be able to determine if the data that is going to be bound to these areas is going to fit or not (not get cut off/cover something else basically),somehow mark the products(the data coming in from the angular service) to symbolizes which template it best fits into, or even write/modify the template on an individual product basis and save a copy for each product that I could have the component reference instead.
I am partly able to do this with some basic jquery within the component checking the natural width and height of objects coming into the templates, but it REALLY slows down page load, so it's not viable
I came to the conclusion that I should use a custom webpack to do this, possibly write a loader that analyzes the data coming in from the angular service and figure out which template that specific product fits best. The loader could do the calculations to figure out what fits where.
The reason I want to do this in the webpack is because I ultimately need to do the calculations anyway, and it would really bog down the load time to try and do this much logic dynamically on user load, not to mention it's just redundant in my situation to figure this out more than once, as the product info will not change until the website is updated with a new API call anyway.
I currently have a property hard coded that indicates which template to use(a number corresponding to a template), but doing it this way limits the scope of possible templates, and opens up many possible programmer goofs, as well as the fact that it doesn't cover smaller issues that ARE noticeable, and becoming a problem.
So, my question has three parts:
Is it possible to call an Angular Service/API call in general within a loader.js/ts file?
Can I manipulate the data coming in from an Angular Service/API call and have it preserve those changes (changing a flag property of each product coming in from the service)? The interface in angular that handles the data coming in has an extra property that I could assign potentially in the webpack to denote which template to use.
Could I write html files to a folder on the local project/to a database using that data from a service and the base templates?
I apologize for the wordiness, but the situation has a lot of unique parts that I feel are necessary to include. I don't need code examples so much as I just need to know if Webpack/Loaders can/should even do this. I'm obviously open to any suggestions as well as to other ways to solve this problem.
Notes:
All the code I really have so far for the webpack would be configuring my angular.json to run off of a custom-webpack.config.js file I created, it doesn't currently do anything.
The service executes an http request and is subscribed to by angular components that consume it's data, but I could possibly write a js promise and recreate the interface for the scope of the webpack/loader, which is why I think it may be possible.
When programming in Meteor I often find myself having to sprinkle typechecks or existence checks a bunch when writing Template helpers (at least under a couple very common conditions).
A helper for one template depends on a collection loaded by a different template
Any time a template helper operates on a piece of the DOM that another template is responsible for rendering into existence
For example (in the first case):
Template.example.rendered
rev1 = getRev(revId1)
revText1 = html2plain(rev1.text)
where getRev is doing an operation on the Revisions collection that may or may not be loaded by the time the example template is first rendered. So rev1.text will sometimes throw an exception because getRev ends up returning null or undefined if called before Revisions is loaded.
I then end up having to check a ton of variables/objects throughout my code for existence before using any of their properties just to be safe.
I could imagine using a router to not render my example template until after a different collection is ready (but for nested templates, and Session variable changes this doesn't work so hot).
I could imaging wrapping the helper code in a if (isCollectionReady) which might help but doesn't seem best practice.
The question is: Is there a canonical or best practice way to, identify these situations, code for them, or avoid this altogether?
Meteor is designed such that its templates are reactive, so that in most cases you shouldn't need to do DOM manipulations on them. As the underlying data changes, the templates automatically rerender so that they're always showing the latest data. Take a look at the examples in the Meteor docs: they don't use any DOM manipulation code. The templates put the data into the right places, and that's all they need.
In my experience there are two common reasons to need to put code into rendered:
You're loading a widget that needs to be initialized after the template is rendered and ready, like a <select> replacement.
You're doing animations. (In this case, I usually tell my template to put everything in its proper place but with a CSS class that hides the elements, and then all rendered does is animate the reveals.)
It's usually fine for a template to render before its subscription has loaded; at worst, the template will just render blank and then rerender as the data streams in. Also remember that you can subscribe from client-side code other than a template helper, for example Meteor.startup on the client side. Finally don't forget about the created helper; if you really want to wait until a template is loaded before subscribing, that would be a better place to subscribe than rendered, as it gets called sooner.
What DOM manipulations are you doing and why? Assuming you're not using widgets or animations, chances are that you can achieve what you want by using templates on their own without any additional manipulation code.
I often use data-attributes to store configuration that I can't semantically markup so that the JS will behave in a certain way for those elements. Now this is fine for pages where the server renders them (dutifully filling out the data-attributes).
However, I've seen examples where the javascript writes data-attributes to save bits of data it may need later. For example, posting some data to the server. If it fails to send then storing the data in a data-attribute and providing a retry button. When the retry button is clicked it finds the appropriate data-attribute and tries again.
To me this feels dirty and expensive as I have to delve into the DOM to then dig this bit of data out, but it's also very easy for me to do.
I can see 2 alternative approaches:
One would be to either take advantage of the scoping of an anonymous Javascript function to keep a handle on the original bit of data, although this may not be possible and could perhaps lead to too much "magic".
Two, keep an object lying around that keeps a track of these things. Instead of asking the DOM for the contents of a certain data-attribute I just query my object.
I guess my assumptions are that the DOM should not be used to store arbitrary bits of state, and instead we should use simpler objects that have a single purpose. On top of that I assume that accessing the DOM is more expensive than a simpler, but specific object to keep track of things.
What do other people think with regards to, performance, clarity and ease of execution?
Your assumptions are very good! Although it's allowed and perfectly valid, it's not a good practice to store data in the DOM. Sure, it's fine if you only have one input field, but, but as the application grows, you end up with a jumbled mess of data everywhere...and as you mentioned, the DOM is SLOW.
The bigger the app, the more essential it is to separate your interests:
DOM Events -> trigger JS functions -> access Data (JS object, JS API, or AJAX API) -> process results (API call or DOM Change)
I'm a big fan of creating an API to access JS data, so you can also trigger new events upon add, delete, get, change.
I was watching a video on making a good javascript application infrastructure. Basically what it said was:
Your application consists of components
Components are parts of the page that can act on their own.
components can be registered into te application.
upon registration, they get their own sandbox.
A sandbox is an component's interface to the application core.
The core is built on top of a javascript library.
Components only have access to their sandbox, not to other components, nore the core or the underlying library.
Now, what I'd like to make is an application where you can easily make new components. Components have their own part on tha page, their own div in which they can work. And here comes the first part of my question: I want to give these components a copy of the jQuery object, but that has an internal restriction applied so that it can only work inside a certain containing element.
The second part is,that even if a component has limited access to the DOM using jquery, it can still access the document. I have tried both setting Window and Document to null, before running my test script, but the browser doesn't allow this. Is there any way that I can truly restrict the possibilities of an object to the methods of 1 object that I pass to it?
You're mis-understanding the point here. The intention isn't "make it 100% imposible for a component to acces anything it shouldn't". The ONLY way to do that is the insanely complicated step that Facebook took which is to parse the JS/HTML code and re-write it to dis-allow certain references, etc. I'm betting it took their dev team 1,000+ hours to do and there are still holes in it.
Basically the intention is to give each component a sandbox to play with and then say "please only use this". The authors then comply with the request.
Your sole other option is iFrames, in which case a component can do whatever it wants and it won't effect anything (assuming you're on a different sub-domain and you provide a parent-window proxy).
I want to load an HTML page with existing data (a list of comments or widgets or whatever), then use Javascript to render additional data in the same format as it is input by users interacting with the page.
I'd like to use a model stored in a JavaScript object that represents both existing data on the page as well as new data from user input, then observe to the model to update the DOM when it changes.
I'd like to render JS templates to display data entered by users quickly, without hitting the server again.
I would like to avoid writing server-side and JavaScript templates that render the same data.
To solve the first problem of building the initial model it seems like the options are, in order of preference:
Use JavaScript to pull the data rendered in HTML to build the initial model, or
Render JSON directly to the DOM and build the JS object from that, or
Hit the server again after the page is loaded as an ajax call to get the data as JSON
To avoid having server-side and client-side templates to display the same thing:
Use use something like Pure to build templates from the DOM, or
Only use JS templates and use one of the second options above to initially render the page (populate them from JSON rendered to the DOM or make an ajax call to get JSON to populate them).
Use a templating system that works on both the server and client.
I feel like none of these solutions are particularly elegant, and I'm curious as to what other patterns I may not have thought of or if there is a common solution.
My environment is Rails 3, but the problems are applicable to any server -> HTML/JS setup. I can see how some of this might be easier with something like Node.js but I'm principally interested in solutions that would apply to Rails.
There's so many ways to accomplish this. I have been struggling with this same issue. I think that once the complexity of your web app reaches a certain threshold you have to resort to javascript to keep the state correct. Jquery (among other dom manipulation frameworks) really help but at a certain point it can become spaghetti code.
I just touched this binding javascript library called Knockout. It's pretty elegant and simple to use it tries to follow the MVVM pattern by allowing you to create a ViewModel with observables that you can bind html elements so that their values and attributes change based on your ViewModel values.
If you're creating dynamic html you can always embed the initial values of the javascript ViewModel along with the html of the page so that you can avoid that initial ajax call.
Out of the box it is compatible with jquery templates which just makes dom manipulation a breeze. I've just started using it and I'm loving it so far.
Hope that helps.