Editors and Widgets
A file editor uses
project_file.coffee. A family of file editors is the set of editors which use the same store. Each family of editors has its own folder inside
smc-webapp/. Inside this folder is typically the following
Additional supporting files are also common:
Treat these folders somewhat like modules. Typically you will only be importing from
Widgets stand alone and do not call
register. See "smc-webapp/widget-markdown-input/" for an example.
Actions, Tables, Stores, Oh My!
We use CQRS = command query responsibility segregation.
It means that you have two different things you communicate with (e.g., "Actions" and "Store"). One is used only for commands (=actions). The other is used only to get out data (=store). Segregation means they are completely separate. It's the design pattern we're using.
If something doesn't fit into that at all, and you don't want to change the store or UI to reflect that, then that something should be somewhere else -- not in actions or store. CQRS = command query responsibility segregation.
Store functions should always be pure functions
Computed values are
Only get called when a component is rendered which depends on the function
Callable from outside React code
Not stored in the redux state. Maintain redux state as pure data
Importing them in a high level component:
Importing values from outside stores
Run time store definitions can be created as follows:
Actions are called to make state changes. They do not directly manipulate the UI.
Q and A
[hsy]> How to change a value in a store? What patterns are preferred?
[hsy]> What are the steps to make a react component actually "react" to changes in a given store?
details to take care of? (e.g. control exactly when to re-render)
The following questions are specific for projects, but are meant to be general:
not project related, maybe callback, maybe return value, doesn't change store → misc
project related, maybe callback, no return value, doesn't change store → store ? (e.g.
No. The methods of the store should all be "pure" functions of the immutable js state. There should be no callbacks ever, and nothing that should have any impact on any state anywhere. The store is a container of state and the interface is "ways to get at that state". (Exception: there is a method called "wait", which calls a callback when a certain condition on the store holds.)
project related, maybe callback, has return value, doesn't change store → somewhere else ?
Somewhere else, e.g,. a module scope function or class or function in client.coffee. We want to minimize these as much as possible, as they are harder to reason about, but obviously sometimes they are necessary. Example: synctables involve tons of such methods.
project related, no callback, no return value, changes store → action
Yes, that's the ideal case. These can of course be asynchronous functions -- e.g., copying a file -- but rather than expressing what happens as it progresses via callback(s), the instead update the store as the run. Then the UI can display what happens (or not).
project related, has callback, no return value, maybe changes store → action, but only for "internal" methods
Yes, to write clean code the non-public api for Actions can have all kinds of such "traditional" methods.
project related, no callback, has return value, changes store → shouldn't exist at all
Of course, nothing is perfect -- the above is our design pattern, what we should rewrite everything to do, etc., but mistakes have been made.