I'm working on building an step sequencer in Redux to help me learning. What I need is some universal clock that functions as "tick" to provide musical timing.
So I planed to use the Tone.js library, which builds on top of the Web Audio API.
There's the following function:
Tone.Transport.scheduleRepeat(function(time){
//do something with the time
}, "8n");
You provide a callback function which gets called everytime the transport reaches a certain position.
My naive approach was to let the callback dispatch an action which increments a tick count in my store.
This doesn't work because actions have to be plain objects.
What are the possibilities to get this working?
I'm still working on getting the right understanding of the basic underlying principles of Redux so I'm unsure about that but could I somehow
catch the callback using middleware and just let it through when it is actually invoked?
Would this be the right direction? What are some libraries, examples or concepts I could look into to get some idea how this could be done?
Is this even the right direction or should I approach this differently? If so, how?
Or do you maybe have any idea what's the best way to provide global timing for different components in a Redux app?
I went into a lot more detail in https://www.html5rocks.com/en/tutorials/audio/scheduling/, but in short - you shouldn't use Javascript callbacks for musical timing. It's not accurate enough. That's why we have web audio scheduling.
Very interesting question, that's a pet project I've been also wanting to tackle but haven't written a single LOC yet. :)
For the timing part, you could use a middleware for that, or even a <Clock /> component that launches the scheduler itself and dispatches an action on every tick (probably with the time as payload).
The tricky part however is the overall design of your application. Having researched Tone.js a little bit, it was clear to me that you'd have to separate the audio part from the visuals. Which means your Redux state should only be concerned about representing your step sequencer (I'm visualizing something like a list of lanes (channels/instruments) and your audio logic should be kept outside of it.
I would keep an array of lanes, each of which is itself an array of "steps" that define whether they're "active" or not. Again this is only UI related. Clicking on a step to activate it should modify your state via action creator and also setup anything you'll later need to play with Tone.js.
When playing back your song, you'll need to dispatch that clock tick to advance the current active "step" so you can highlight it in the UI.
Here's a mouth-watering Codepen emulating a Roland TR-808 to grab ideas:
http://codepen.io/pixelass/details/adyLPR
And here's the relevant section on the Tone.js wiki on sync'ing audio and UI:
https://github.com/Tonejs/Tone.js/wiki/Performance#syncing-visuals
Sorry I can't help you further, perhaps you're ahead of me and already have some working code you could share.
Basically cwilso responded correctly. If you want to be scheduling JS functions for musical timing, you should not be using callbacks.
If there is Tone.js functionality that you want to implement based on this timing, avoid Redux and call these Tone.js functions directly, either within the callback functions or Tone.Transport.schedule function.
If you are building a sequencer I would recommend looping the Tone.Transport based on the length you want and scheduling the notes to be hit at certain points on the timeline (if this is what you are looking for). Check out the loopStart and loopEnd in the docs for help (http://tonejs.github.io/docs/#Transport).
If this functionality is necessary for visual references, which may be why you want a Redux callback, I can provide an example of how you might do that below:
function incrementTick() {
return { type: 'INCREMENT_TICK' }
}
// inside your component once the increment function has been connected
Tone.Transport.scheduleRepeat((time) => {
this.props.incrementTick()
}, "8n");
Hope this helps.
I'm working on an audio related application and have run into the issue of managing the web audio API part along with redux as well.
The way I've solved it is only storing representation of the audio state in the redux store (plain JS objects; what you would store in the database and use to initialize the app). This stored information is used to render the UI.
I have a service 'engine' class which listens to all changes in the store, this is where all the web audio stuff is created and stored. It contains basically a copy of the reducers from the redux store but applies the changes to the web audio nodes.
For example I dispatch an action:
{type:"set-gain", payload:{trackid:3, value:0.7} }
The redux store will simply update a plain JS track object to the new gain value, the engine will find the associated gain node (or create with add etc.) and set the value on it.
In your case you would dispatch an action to set the timing, in the redux store save it as plain JS object, in the engine part you use web audio scheduling to set it.
Related
Let's add a <FlatList/> into our application.
The first requirement we have is to render a predefined set of 5 items. We define a constant in our component, pass it into the list via the data prop and it works just fine...
... until we decide to store this data on a server and expose it via the API. OK, no problem, will fetch the data in our componentDidMount() method, put it into the state when it finishes loading, pass the state to the data prop and it also works just fine...
... until we notice that we have a huge delay before we can show the first item of the list. That is because the amount of data we're loading from the API grew significantly over time. Maybe now it is some REST resource collection consisting of thousands of items.
Naturally, we decide to implement a pagination in our API. And that is when the things start to get interesting... When do we load the next page of the resource collection? We reach out to the wonderful React Native API reference, examine the FlatList part of it, and figure out that it has a very handy onEndReached callback prop. Wonderful! Let's load the next page of our collection every time this callback is called! It would work as a charm...
... until you receive a bug report in your mail. In this report a user tells us that the data is not sorted properly in the list, that some items are duplicated and some items are just missing.
After a quick debugging we are able to reproduce the issue and figure out what causes it. Just set the onEndReachedThreshold = { 5 } and scroll the list very fast. onEndReached callback would fire asynchronously before the previous one has finished.
Inside our component, we have a variable pageId storing the last page ID we loaded. Each time the onEndReachedThreshold gets fired we use it to construct the next page URL and then increment it. The problem is that this method is called concurrently and the same value of pageId is used multiple times.
I used to do a bit of multithreading programming before, I've heard of mutexes, semaphores, and atomicity. I would like to be able to acquire an exclusive lock on the pageId to use it in this concurrent callback.
But after a quick Internet search, it seems that JS does not provide such tools out of the box. I found some libraries like this one but it doesn't look like a good candidate for a dependency, it's not very actively developed, it's not made by a major vendor etc. Looks more like some hobby project.
The question is: what are the industry-standard rock-solid tools or patterns for thread-safe React Native programming? How can I solve the described concurrency issue in a React Native application?
So we are about two months in on a project. This is the first time I have ever managed code writers and not written the code myself. I've been reading their code for the last week. What was suppose to be a simple React app has turned into a spaghetti mess.
I understand: redux helps to manage global state. But should that mean that all buttons should map to a global "action?" This has seemed to create this entire mess of objects scattered throughout the entire app. I keep asking myself, why are we using global state for everything when local state could be used for 90% of the application. This is the kind of code that gives me heartburn:
let subitems = SidebarItems[state.type].sub_items;
Store.dispatch(SidebarSubItemHandler(item.action, subitems[0], null));
if(item.sub_items[subitems[0]].param) {
browserHistory.push(`${item.sub_items[subitems[0]].path}/${item.sub_items[subitems[0]].param}`);
} else {
browserHistory.push(item.sub_items[subitems[0]].path);
}
subItembuttons = Object.keys(this.props.subitems.sub_items).map(subitem => {
let subItem = this.props.subitems.sub_items[subitem];
return <li className={this.props.activeSubItem.action == subItem.action ? "bottom-bar-item active" : "bottom-bar-item"}
onClick={e => this.props.onClickSubItem(e, subItem)}
key={subItem.action} style={this.props.subitems.inlineStyles.mobileSubItemLI}>
{subItem.item}
</li>;
});
The application is littered with all kinds of objects like these that map to "action" objects. So at this point we are making the decision to scrap the entire project and restart from scratch, but without redux. Let's try to do as much as possible using local state only. When it comes time, and we need global state for something, ONLY implement it for that something, not every single action in the app. Does this make sense?
So I guess my question is: If we develop an app using local state and just fundamental React, will we be creating un-reversable problems that would prevent us from implementing redux on a per item basis?
Quoting from the relevant Redux FAQ entry at http://redux.js.org/docs/faq/OrganizingState.html#organizing-state-only-redux-state:
Using local component state is fine. As a developer, it is your job to determine what kinds of state make up your application, and where each piece of state should live. Find a balance that works for you, and go with it.
Some common rules of thumb for determing what kind of data should be put into Redux:
Do other parts of the application care about this data?
Do you need to be able to create further derived data based on this original data?
Is the same data being used to drive multiple components?
Is there value to you in being able to restore this state to a given point in time (ie, time travel debugging)?
Do you want to cache the data (ie, use what's in state if it's already there instead of re-requesting it)?
Per your specific question: if you use the "container component" pattern fairly consistently, it should be relatively straightforward to swap those "plain React" containers for Redux-connected containers down the line. See https://github.com/markerikson/react-redux-links/blob/master/react-component-patterns.md#component-categories for articles on the "container/presentational component" pattern.
Two other thoughts. First, I recently co-authored an article that discusses why you might want to use Redux in a React application.
Second: yeah, that code looks kinda ugly. I'm hoping those are at least three different snippets from different parts of the codebase, rather than one snippet, but that's rather hard to read. The repeated use of "sub_items" and "subitems" seems like a bit of a red flag, readability-wise.
It also doesn't look like it's following good Redux practices. For example, idiomatic Redux code almost never references the store directly. Instead, references to dispatch and getState are available via middleware, and thus can be used in action creators via redux-thunk and redux-saga. Connected components can also access dispatch.
Overall: you are absolutely welcome to use as much or as little Redux as you want, and as much or as little local component state as you want. I think the larger issue, though, is how well your team actually understands Redux, and how they're trying to use it.
I'm writing a react/redux app that has a Job object that fires Events from time to time. On these Events the user is expected to react. I can easily write the React component that shows such a job or events, but don't know where to put the logic when
the user is not on the Job page
and an Event happens
and I would like to pop up a notification
Of course, once I get access to the store, I can create the notification too.
Shall I handle such logic in a React container that render() nothing?
Or handle it with vanilla JS when I load a Job data?
Or to handle it in the reducer when the data is stored? (probably not recommended)
My problem with the option two is that I don't know how to access the redux store from a totally ad-hoc code, as my store is not a global object.
What do you recommend?
Generally speaking, the two places that you'd put code that needs to access the store (for either dispatching or receiving state updates) is in middleware or a connected component. If you specifically want to respond to an action coming through, then you would need to use middleware.
I actually threw together a sample timer middleware in a chat discussion a few weeks ago. I just pasted it as a gist here as an example: https://gist.github.com/markerikson/ca96a82d6fdb29388aca4052a9455431 . Illustrates the idea of doing something asynchronously in the background.
You may also want to look through the list of middlewares in my Redux addons catalog: https://github.com/markerikson/redux-ecosystem-links/blob/master/middleware.md . Numerous examples of ways to execute background-ish logic.
Finally, https://github.com/yelouafi/redux-saga (which is itself a middleware) is a fairly common lib used to do background-ish logic.
One of the goals of Flux is to make the app more predictable by reducing crazy tangled dependencies. Using the Dispatcher you can define a strict order in which the Stores are updated. That creates a nice tree dependency hierarchy. That's the theory. Consider following situation:
I have a game. The store sitting at the top of the hierarchy is StateStore that holds only the current game state, i. e. playing, paused, over. It is updated via actions like PAUSE or RESUME. All other stores depend on this one. So when a store handles some kind of update action (i. e. MOVE_LEFT), it first checks the StateStore and if the game is paused or over, it ignores the action.
Now let's say that there is an action that would cause game over. It updates some store and the store decides that the game shouldn't continue ("the game character moves left and falls into a trap"). So the state in the StateStore should change to over. How do I do that?
Theoretically, it should go like this:
The given store is updated first and reaches the point of game over
The StateStore is updated afterwards (it waitsFor the other store), checks the other store and switches the state to over.
Unfortunately, the other store needs to access the StateStore as well to check the current game state to see if it should be updated at all (i. e. the game is not paused). They clearly depend on each other.
Possible solutions:
Merge such stores into one store. That would probably cause my whole app to collapse into a single store which brings up the question whether Flux in this case is a good idea.
Distinguish update order and read-only dependencies. All stores would be updated in a strict order, however they could read from each other arbitrarily. The StateStore would therefore for every action check all existing stores and if any of them indicated game over, it would change the state to over, effectively preventing all other stores from updating.
What do you think?
In Flux stores should be as independent from each other as possible and should not read from each other. The only way to change their state is through actions.
In your case, if some store decides that the game is over — you should update a StateStore from the ActionCreator. You can do it by calling a HaltGameActionCreator from the store or by dispatching a HALT_GAME action from ActionCreator that triggered the store change in the first place.
For those having the same issue, you can read here about the actual application I had this problem with and how I approached it. Long story short, I allowed all the stores to arbitrarily read from each other (the suggested solution no. 2).
Note that ES6 modules allow circular dependencies which simplifies the implementation.
Nevertheless, looking back I'm not sure if it was a right decision. If a piece of business logic inherently contains a circular dependency, we should not try to apply a solution that doesn't really support it just because somebody says so. Flux is only one pattern, there are many other ways how to structure the code. So perhaps I would recommend collapsing the whole logic into a single store and use one of the other ways to implement the store itself (e.g. standard OOP techniques).
I would also consider using redux with reselect instead of Flux. The problem with the original example is with the StateStore that depends on two different inputs. It can be changed either by the user explicitly pausing/resuming the game, or by the game situation reaching game over. The advantage of this approach is that you need to check only one store to get the current game state.
With redux/reselect, you'd have one reducer handling pause/resume actions and another reducer handling the game situation. Then you'd have a selector combining these two pieces of information into the final game state. Most of the business logic would be moved from the stores to action creators, i.e., in the moveLeft() action creator, you'd use this selector to check the game state and only then you'd dispatch MOVE_LEFT action.
Note that this is just a rough idea and I don't know if it's viable.
I'm trying to understand the Flux example chat app. The authors mention this unidirectional data flow:
However, in the example app there are dependencies between Action Creators (ChatMesssageActionCreator) and Stores (MessageStore), and between Stores (MessageStore, ThreadStore) and Web API Utils (ChatMessageUtils), which seems to be against the unidirectional data flow rule:
Is it recommended to follow the given example, or should one design a better pattern?
Update
I figured out that the ChatMessageUtils doesn't belong to Web API Utils, so the two arrows from store shouldn't point there, therefore maybe they're okay.
However the connection between the ActionCreators and the Store seems still strange.
The example is a bit forced, and it was created with the purpose of trying to show how waitFor() works. The WebAPI aspect of the example is pretty half-baked and really should be revised.
However, even though MessageStore.getCreatedMessageData(text) passes a value to the store, it's still a getter. It's not setting data on the store. It's really being used as a utility method, and a good revision (pull request?) would be to move that method to a Utils module.
To improve upon the example for the real world, you might do a couple things:
Call the WebAPIUtils from the store, instead of from the ActionCreators. This is fine as long as the response calls another ActionCreator, and is not handled by setting new data directly on the store. The important thing is for new data to originate with an action. It matters more how data enters the system than how data exits the system.
Alternatively, you might want to have separate client-side vs. server-side IDs for the messages. There might be few advantages of this, like managing optimistic renderings. In that case, you might want to generate a client-side id in a Utils module, and pass that id along with the text to both the dispatched action and the WebAPIUtils.
All that said, yes the example needs revision.