Given this component tree:
c0 - c11 - c12 - c13
\
c21 - c22
What is the best way to send some data from c13 to c22 ?
In my case I had something like forum page(c0): there were message feed (c11), message (c12), "quote" button (c13) and block with some controls (c21) including message form (c22).
What I wanted is to add some text to message form on quotation click.
So I added callback (via prop) onQuote to message that is just being called with message text (with some transformations) like this: this.props.onQuote(txt). Then I provided it from root component (c0) via passing it in a chain: c0 - c11 - c12. And since text in message form is kept in c22 state I had to create method like .setText(txt) and create delegation from c21 to call it from c0.
This looks pretty bad (another word, actually) and complicated (too much code) to me.
How would I do better? I don't wanna use global state and I don't believe that this is the react way to do things. I don't really like the whole "passing" thing when there're many components in the middle that do nothing with data but just pass it.
The preferred and proposed method by Facebook itself is to lift up state to at least to the nearest common ancestor of both components.
Related
This is really weird. It took me many hours to figure out how to fix this. But even with it fixed, I don't know why it breaks in one configuration but not the other.
The best way to explain this is with the StackBlitz live example: https://stackblitz.com/edit/react-collapse-transition-breaks-with-dynamic-key
The live example details the exact issue, but here's the synopsis:
It's a React app using Material UI.
I have a <List> that is populated with an array of <ListItem>s.
Those <ListItem>s are clickable. When you click them, it uses the <Collapse> transition to expose a sub-<List> of "subheaders". The subheader <List>s are also populated with an array of <ListItem>s.
Here's where it gets weird: I have a simple <div> that holds the "header" <ListItem>s and the <Collapse>-ible <List> of "subheaders".
Because these are part of an array, React complains if I don't add a "key" attribute to top-level element (the <div>).
If I add a dynamically-generated key value to that containing <div>, it somehow kills the transition animation on the <Collapse> element. The <Collapse> still opens-and-closes, but it doesn't animate over a set number of milliseconds. It just opens (immediately) or closes (immediately).
If I add a static key value to that same containing <div>, the animation works just fine.
Why does the dynamic-key approach break the animation??
TLDR: Do not dynamically-generate globally-unique keys for array elements in React.
OK, after repeated attempts at Googling, I think I finally understand what's going on.
When you add items to an array in React, a warning is thrown if you don't add a unique "key" to each element in the array. As long as you use something unique as the "key" value for each element, the warning goes away and, for the most part, React seems to manage the array elements just fine.
When I was starting React development (a few years ago), I thought, "I can solve this easily by using a random GUID-generating function to add unique keys to all my array elements. So I would frequently use code that looks like this:
let newArray = [];
someMasterArrayOfObjects.forEach(object => {
if (someConditionIsMet) {
// SEE HOW CLEVER I THOUGHT I WAS?? USING A RANDOMLY-GENERATED GUID QUIETS THE
// UNIQUE-KEY WARNINGS THAT ARE THROWN BY REACT
newArray.push(
<div key={createRandomGuid()}>
{object.title}
</div>
);
}
});
But I missed one key word from the ReactJS documentation (emphasis, mine):
Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a STABLE identity:
They use the word "stable" a few times in the documentation, but it didn't really sink into my thick skull. Like most devs, my first concern was removing the warning that is thrown when array elements are missing a unique key. And using a randomly-generated GUID solved that problem.
But React uses those keys to figure out what should be re-rendered during state changes. If you randomly-generate a new, globally-unique key every time you build the elements in the array, then React will assume that all of these elements need to be completely rebuilt from scratch every time you set state.
At the very least, this is inefficient. You may not notice any performance effects in small arrays/apps, but there's no reason to artificially force a re-rendering of every array element every time that state is set for any reason. You may not notice any visual problem in your app, but it's poor practice.
At the worst, it will actually break some of your functionality. In my case, it was breaking the <Collapse> transition animation because the rendering engine couldn't compare the incremented "height" value between one state change and the next - because on every attempt to change that height, I was assigning a brand new, globally-unique identifier to the "key" value and React was seeing it as an entirely new, entirely different component.
Once I finally figured out what to Google, I also found this great JSFiddle:
http://jsfiddle.net/frosas/S4Dju/
Notice that the center row of inputs in his example are titled "Unique random keys". When you manually change the value of one of the those unique random keys, then you click on "Add item", it blows away the results of your changes, because it re-renders the input elements as brand-new elements with no ties to their previous state.
How do I handle more than one condition (with different boolean expressions) in a UML state machine transition (as guard)?
Example:
In this example I would like to add more than only one condition (Tries < 3) in the transition from "logging in" to "Logged In" like discribed in the note.
How to handle this UML compliant?
Simply spoken (and to focus on the needed step)
put a boolean condition like above in the Guard. This can be any text. You can write C-style or plain text. I'm not sure about OCL here, but that's for academic purpose anyway (my opinion).
N.B. Your diagram shows Tries = 3 which should be a Guard also (i.e. [Tries = 3]) rather than a Name.
There are a couple of options here:
Your guard condition can combine multiple checks within the '[]' - much like you were doing in the note.
You can have multiple transitions between the same two states, each with its own condition.
You can have states within states. So in your example the three states could be within a superstate of 'Normal Operation' - which you then further define in other documentation or via a note.
All of these are valid UML syntax. But note that just because something is valid doesn't mean it will be supported in your editor. For example it was many years before most of the features of sequence diagrams became available within editors...
I'm writing a Clojurescript app, using Reagent to make my components reactive.
I have a simple question. Should I
Pass my atoms as inputs through my components, or
Use the atoms as global variables and let them 'side-affect' my components?
In the tutorial they use the latter option, however in trying to keep my functions pure I opted for the former.
Am I correct in saying that using them as global variables (in addition to being less verbose when defining component inputs) prevents re-rendering of whole parent components where the atom's state is not used?
If you make your components accept atoms as arguments, then you can make them much more reusable and easier to test.
This is especially true if you opt for keeping your entire application state in a single atom, then passing it down to child components using cursors.
;; setup a single instance of global state
(defonce app-state
(reagent/atom {:foo 0 :bar 0})
;; define a generic counter component that knows
;; nothing about the global state
(defn counter
[count]
[:div
[:button {:onclick #(swap! count inc) "+"]
[:span #count]])
;; define counter components and give them access to
;; specific context within the global state
(defn app
[state]
[counter (reagent/cursor app-state [:foo])]
[counter (reagent/cursor app-state [:bar])])
You can even go one step further if you decide to use Reagent with Re-frame. Re-frame encourages you to build your app with a specific architecture that looks something like this.
app-db > subscriptions
^
handlers v
^
events < components
Rather than just writing components and hooking them straight up to a global atom (app-db), you write subscriptions which are just functions that select/query some data from app-db and pass it along to components whenever app-db is changed.
Then, rather than a component messing around with app-db directly, the component creates events which are just small pieces of data that describe the intent of the component.
These events are sent to the handlers, which are functions that take the event and the current app-db as arguments and return a new app-db. Then the existing app-db is replaced, triggering the subscribers to pass data down to the components and so on.
It's definitely helpful if you find your Reagent project getting a bit tangled up and the Re-frame readme is a great read, whether you decide to use it or not.
I prefer passing a ratom to the component.
Re-frame is becoming popular https://github.com/Day8/re-frame
Passing a ratom in does not make your function any more pure, the atom can still be side-effected. It does make your components more flexible and reusable because they define their dependencies.
It does not affect the re-rendering directly whether you refer to a global db or a passed in db. The signal graph of when to render is built from occurrences of deref inside the vector, which doesn't care about where the ratom comes from. However you can be more efficient by creating reactions.
(defn my-component []
(let [x (reaction (:x #db)]
(fn []
[:div #x]))
This component will only re-render when :x changes (not when anything changes in db. Creating reactions can become tedious, which is one of the appeals of re-frame.
(ns whip.view.reactions
(:require [reagent.core :as reagent]
[devcards.core :refer-macros [defcard-rg deftest]])
(:require-macros [reagent.ratom :refer [reaction]]))
(def a (reagent/atom {:x 100 :y 200})) (def b (reaction (:x #a)))
(def c (reaction (+ #b 10)))
(defn view-c []
(prn "Rendering view-c") [:div
[:div #c]
[:button {:on-click (fn [e] (swap! a update :x inc))} "inc x"]
[:button {:on-click (fn [e] (swap! a update :y inc))} "inc y"]])
(defcard-rg reaction-example [view-c])
Reactions are a very concise way to express data ow. Here you start with a ratom containing x
and y values. You then build a reaction b that only observes the x value. Next, introduce another reaction c that observes the sum of b and 10. Then create a component that renders c reactively. Observe that when you click the “inc x” button, the view is updated with the result of applying the expressions. When you click the “inc y” button, nothing happens. Check the console to con rm that the “Rendering view-c” message is only printed when clicking “inc x”. This is a very good thing, because the view does not depend on y in any way. If you were to deref a instead of c in the view, it would be re-rendered even if y changed.
Reagent reacts to reactions and ratoms via requestAnimationFrame. So, changing many ratoms and reactions that depend on them only results in one render phase.
I have been reviewing some material on the representation of an AI plan given the STRIPS format, and found that different people seem to formulate the same problem in different ways.
For instance, Wikipedia has an example regarding the Monkey in the lab problem. The problem states that:
A box is available that will enable the monkey to reach the bananas hanging from the ceiling if he climbs up on it. Initially, the monkey is at A, the bananas at B, and the box at C. The monkey and the box have height Low, but if the monkey climbs onto the box, he will have height High, the same as the bananas. The actions available to the monkey include Go from one place to another, Push an object from one place to another, ClimbUp onto or CLimbDown from an object, and Grasp or UnGrasp an object. Grasping the object results in holding the object if the monkey and the object are in the same place at the same height.
Here is the Wikipedia plan (please note that it is not matched exactly to this problem description, but it is the same problem. It doesn't seem to implement Ungrasp, which is not important for this discussion):
Now nowhere in this plan can I see that the bananas are located at Level(high), so the only way this could actually be divulged from the plan would be to read through the entire set of Actions and deduce from there that the Monkey must be at Level(high) to interact with the bananas, hence they must be at Level(high).
Would it be a good idea to put this information in the Initial State, and have something like:
Monkey(m) & Bananas(ba) & Box(bx) & Level(low) & Level(high) & Position(A) & Position(B) & Position(C) & At(m, A, low) & At(ba, B, high) & At(bx, C, low)
It looks quite verbose like that, but at the same time, it allows the reader to understand the scenario just through reading the Initial State. I've also been told that we should not be using constants anywhere in STRIPS, so I thought declaring the A, B, and C as Positions was a good idea.
Is it that some people do it differently (which I feel would kind of ruin the idea of having a standardized language to represent things), or is it that one of the ways I have presented isn't in the correct format? I am new to STRIPS, so it is entirely possible (and likely) that I am missing some key points.
This is not the greatest wikipedia ever. The description of STRIPS is accurate, but a little outdated.
Generally you don't need to worry about defining all the variables in the initial state because the variables are defined by the domain (the P in the quadruple in the linked article). For an intuition as to why, you have an operator for MONKEY in your initial state, but you're still introducing a free variable m that is not defined anywhere else. You end up with a chicken and egg problem if you try to do it that way, so instead the facts in the system are just propositional variables which are effectively sentinel values that mean something to the users of the system, not the system itself.
You are correct that you need to define the level for each item as part of the initial state, but the initial state of the example actually correct considering the constraints that the bananas are always high, the box is always low and the monkey is the only thing that changes level. I would probably change the example to have the At proposition take into account the object in question instead of using different proposition names for each object but that's just a style choice; the semantics are the same.
Operators in STRIPS are generally represented by 3 distinct components:
preconditions - each variable in the preconditions list must exactly match the corresponding variable in the current state (trues must be true, falses must be falses) but you ignore all other variables not explicit in the preconditions
add effects - when the action is performed, these are the effects that variables that are added to the state
delete effects - when the action is performed, these are the effects that are deleted from the state
and sometimes a 4th cost component when considering cost optimality
The post conditions listed in your example are the union of the add effects and delete effects. The advantage of separating them will come later when you get into delete relaxation abstractions.
In your proposed initial state you have propositions that contain multiple properties for the same object (e.g. At(bx, C, low)). This is typically avoided in favor of having a proposition for each property of each object in the state. Doing it this way makes you end up with a larger state, but makes for a much simpler implementation since you don't have to decompose a state variable in order to identify the value of a specific property of an object in the preconditions list.
I tryed to create a group box with the _createChildControlImpl()-Methode but the layout looks like crap as you can see her http://tinyurl.com/odzgy3v
But when I implement it without _createChildControlImpl() it works fine: http://tinyurl.com/kwzvdm2
Could anybody please tell me what's the reason for this? Thanks in advance!
Have a look at your browser console - there is already a hint.
When you introduce child controls qooxdoo can't reuse the former default appearance of widgets because the appearance id changed (from "groupbox" to "widget/groupBox"). So you have to add your own appearance theme (which can simply forward by using an alias):
qx.Theme.define("test.myAwesomeTheme", {
extend : playground.theme.Appearance,
appearances :
{
"widget/groupBox" : "groupbox",
}
});
qx.theme.manager.Appearance.getInstance().setTheme(test.myAwesomeTheme);
I'm extending playground.theme.Appearance here which extends qx.theme.indigo.Appearance which again extends qx.theme.simple.Appearance. And their you have the groubox definition we are forwarding to.
Here is the complete playground sample.
You are supposed to implement _createChildControl, but not call it directly. Instead call getChildControl in your constructor and let it call _createChildControl, if needed, since it is also caching the result.
GroupBox seems to be a bad fit for what you want - it seems to assume identically sized and shaped elements inside its frame sub-widget, when filled from within the implementation of _createChildControl().
Use another Composite() inside the main container instead, add "Registration" as yet another child control of type label as the first child of the custom widget, and things will look much better (although not identical).
Quick and sloppy proof of concept: http://tinyurl.com/m7ykhta