reduxjs / redux Goto Github PK
View Code? Open in Web Editor NEWPredictable state container for JavaScript apps
Home Page: https://redux.js.org
License: MIT License
Predictable state container for JavaScript apps
Home Page: https://redux.js.org
License: MIT License
I have experiment about ideal redux API for me: https://github.com/vslinko/observable-components-test
wrapActionCreator(actionCreator)()
replaced by performAction(actionCreator())
.performAction()
to async action instead of dispatch()
. Thats simplifies async action API: https://github.com/vslinko/observable-components-test/blob/master/src/actions/items.js#L25What are you think?
As in the docs, the decorator @observes
could couple the counter with the counterStore, instead of giving it the freedom from receiving the counter from any data source via props.
I like flummox's FluxComponent
way of doing stuff: your component is pure and a top-level component chooses how to feed it.
import { Observes } from 'redux/components';
<Observes store="counterStore">
<Counter /* counter={counterStore.counter} */ />
</Observes>
For the @performs
decorator we could have an equivalent component that wires an event of a component (e.g. onClick
, onIncrement
) with an action.
import { Performs } from 'redux/components';
import increment from './actions/CounterActions.js';
<Performs actions={{'onClick': increment}}>
<IncrementButton />
</Performs>
I think we have much more power using components this way. More testable and reusable.
I'm far from being an expert on decorators and even on Flux, so please show your views and let's discuss this thread 😄
Just for keeping track of this.
In many cases it is mandatory to share state between components (e.g. sessionStore
). How can we achieve that using your library since stores are stateless? Could you add an example or an entry to the README?
But I guess I'm too dumb to understand how. Do the docs actually show anywhere how stores/actions/dispatcher interact when not using all the magicality of smart components and shortcuts like bindActionCreators. If they don't consider this a request for more documentation.
<Connector select={fn}>
contract is that fn
takes the root state and returns a plain object. It is essential for the result to be a plain object because:
@connect
, its result is what you'll get as injected props, and React only supports plain object props at the moment.select
return values to determine if an update is needed (a perf optimization).I think we need to enforce that select
returns a plain object. We can use lodash/lang/isPlainObject
to perform this check.
PR is welcome (with a test please!).
@acdlite flummox is using "loose": "all"
in .babelrc
. Babel says that we would have some speed gains from using it but that it might be risky. What are your thoughts/experience with it in flummox so far? Should we include that into redux as well?
It would be more convenient to not have to call bindActionCreators
directly inside the component, so I was thinking that we might able to add something to Connector
and the @connect
decorator to make this nicer? In addition, that would prevent calling bindActionCreators
in render every time (which would provide an extremely slight performance benefit :)).
It seems like the idea of "connecting" could mean connecting to stores AND/OR connecting to actions, if the user wanted. Seems like Connector
is perfect to just mean..."hey, connect this component (or child component) to Redux".
Thoughts?
Similar to rpominov/fluce#4
Can anyone point me to a repo consisting of either of these?
Tests are sorely missing. Gonna try to fill that gap today.
As I understand it, when you update a Store it broadcasts an update to all Connectors. Each Connector selects the slice of State that its interested in and re-renders itself by calling this.setState
. React then recursively renders the component hierarchy until it hits a nested Connector, whose componentShouldUpdate
method compares the old and new props (it also compares the Connector's State, which is guaranteed not to have changed because (a) it's a slice of a Store's immutable State and (b) this nested Connector hasn't called this.setState
). If the props have changed, React continues rendering the component hierarchy. Once React is done, the second, nested Connector receives an update from the Store, selects its slice of State, and re-renders itself. In the worst-case scenario, a linear chain of n
Connectors could result in O(n^2)
render calls.
This is a small example that demonstrates this cascading render effect. Both Connectors are subscribed to the same slice of State, and the parent passes down a prop to the child.
type StoreState = {
user: {
name: string;
age: number;
};
};
@connect(state => ({ user: state.user }))
class Parent extends Component {
render() {
let { user } = this.state;
let displayName = (user.age < 18) ? getFirstName(user.name) : user.name;
return <Child displayName={displayName} />;
}
}
@connect(state => ({ user: state.user }))
class Child extends Component {
render() {
let { user } = this.state;
return (
<ul>
<li>{this.props.displayName}</li>
<li>{this.props.age}</li>
{__DEV__ && <li>this.state.name</li>}
</ul>
);
}
}
This is what I'm currently thinking:
this._state
. This means a Connector always renders with the most up-to-date State even if it hasn't been notified of a change yet. It also means that Store updates are atomic from the perspective of the subscribing views... currently a Connector's props may be derived from the new State while the Connector's state is a slice of the old State.this._state
. If there's no change (e.g. because we already got an up-to-date slice when the parent re-rendered this Connector) then do nothing. If there is a change then we update this._state
and call this.forceUpdate
.The main thing I'm going for is the atomic Store update from the perspective of the React components. From Redux's perspective, the updates are atomic in the sense that it doesn't notify subscribers till the Stores are done transforming the State. But from the perspective of a connected component it's receiving a mix of old and new State as props, while in traditional Flux the components always read a consistent view of the Stores.
Changing the names of props based on number of stores subscribed to seems tricky.
Let's say I have a dumb component that takes a prop board
( { name: 'My Board' }
), which should come from boardStore
:
<Container stores={[boardStore]}
actions={{ addList }}>
{(props) => <Board {...props} /> }
</Container>
But because I only subscribed to one store, it gets flattened and the component only receives name
prop.
If I need to add a subscription to another store userStore
, the props change to:
{
boardStore: { name: 'My Board' },
userStore: ...,
fooStore: ... // (This actually includes data from all stores, not just subscribed.)
}
I think it would be simplest, if the data would never be flattened. Then I can always just do:
<Container stores={[boardStore]}
actions={{ addList }}>
{(props) => <Board board={props.boardStore} /> }
</Container>
Another way could be to pass another function or a map of functions to map the state from stores to
props, but I think I actually prefer the former because of its simplicity.
Right now Connector does a shallow comparison of its old and new props in shouldComponentUpdate
but this isn't guaranteed to be correct if the props are mutable objects. Since the Connector's props aren't managed by Redux it might be right to let the user specify the prop differ or perhaps their own implementation of shouldComponentUpdate
that gets composed with the default one.
I read your flux evolution blog post (very good stuff) and have been looking at the other flux implementations, so far microcosm is looking the best to me. I still have to do research on some of the others you listed but after looking at this projects README I'm not sure I understand what this provides that the other flux implementations you mention don't provide. Could you add a section to the README explaining?
What should redux.dispatch()
return? Currently the code is
function dispatch(action) {
return typeof action === 'function' ?
action(dispatch, state) :
dispatchSync(action);
}
but I don't remember the circumstances when the return value of the callback form can be useful.
Because the callback form may schedule additional dispatch
es, it seems that the calling code still doesn't have enough information. Can we just return whatever action
was passed?
function dispatch(action) {
if (typeof action === 'function') {
action(dispatch, state);
} else {
dispatchSync(action);
}
return action;
}
?
Allowing this would be awesome.
Why did you enforce type
as string
? (createDispatcher.js#L67)
export const INCREMENT_COUNTER = Symbol()
export const DECREMENT_COUNTER = Symbol()
In Flummox we had the ability to auto-dispatch begin
, success
and failure
actions. I assume in redux we can do this by creating a custom middleware, which could inspect the type of the action which returned the promise and then dispatched a success or failure action depending on whether the promise gets resolved or rejected. Does this sound correct to you? If so, would it make sense to include something like this as stock middleware in redux?
I have some example on fluce:
function authFormSubmit(fluce) {
const {valid, disabled, data: {username, password}} = fluce.stores.authForm
if (disabled) return
if (!valid) {
fluce.dispatch(AUTH_FORM_ERROR, new Error('Form is invalid'))
return
}
fluce.dispatch(AUTH_FORM_DISABLED, true)
fluce.dispatch(AUTH_FORM_ERROR, null)
authorize({username, password})
.then(
user => fluce.dispatch(CURRENT_USER, user),
error => fluce.dispatch(AUTH_FORM_ERROR, error)
)
.then(
() => fluce.dispatch(AUTH_FORM_DISABLED, false)
);
}
How to implement same action creator in redux? Should I create action creator for every action type?
I want to use Sourcegraph for redux code search, browsing, and usage examples. Can an admin enable Sourcegraph for this repository? Just go to https://sourcegraph.com/github.com/gaearon/redux. (It should only take 30 seconds.)
Thank you!
<button onClick={() => increment()}>+</button>
to
<button onClick={increment}>+</button>
import {
INCREMENT_COUNTER,
DECREMENT_COUNTER
} from '../constants/ActionTypes';
to
import * as types from '../constants/ActionTypes';
and then use accordingly in case statements, etc..
types.INCREMENT_COUNTER
As per #5 (comment), let's bring back HOCs, but this time built on top of the container components. Container components are lower level.
This work would include:
root
to be a container component called Root
root
and container
as HOCs that wrap the componentsroot
HOC + Container
component in the examplesaddons
folder but keep root
etc as the export name.@hugobessaa
Currently showing an eslint error in the decorators, although Babel seems to work it out fine.
If /src/addons/root.js was changed to:
export default function root(stores) {
return DecoratedComponent => {
class ReduxRootDecorator {
static displayName = `ReduxRoot(${getDisplayName(DecoratedComponent)})`;
render() {
return (
<Root stores={stores}>
{props => <DecoratedComponent {...this.props} {...props} />}
</Root>
);
}
}
return ReduxRootDecorator;
};
}
No eslint errors, babel will assign the IIFE to var, and return it after the class block.
Good idea? Not sure if this is bug with eslint, or an example where you shouldn't return a class due to hoisting.
Was wondering how you handle clashing action and store names in containers. But it also strikes me that since actions are just functions without a current state, they don't have to be passed down from the top. Instead, as long as the dispatch function is available as a prop, you'll still be able to do full dispatches. to explain, instead of -
@inject({
actions: CounterActions,
stores: { counter: counterStore }
})
export default class Counter {
render() {
const { increment, decrement, counter } = this.props;
return (
<p>
<button onClick={increment}>+</button>
</p>
);
}
you could do
@inject({
stores: { counter: counterStore }
})
export default class Counter {
static propTypes = {
dispatch: PropTypes.func.isRequired
};
render() {
const { counter, dispatch } = this.props;
return (
<p>
Clicked: {counter} times
{' '}
<button onClick={() => dispatch(increment())}>+</button>
{' '}
<button onClick={() => dispatch(decrement())}>-</button>
</p>
);
}
alternately
<button onClick={() => dispatch(increment)}>+</button>
but I'm not clear on the benefits (scheduling?)
This would clear up the name clash problem, and make it more 'primitive', if that make sense.
@matystl brings up a great point here:
If you have DRY state than this state is usually not best for ui. Derivated data in their essence are pure functions over multiple store data which returns this data combined somehow. So without any further attempt in component you can subscribe to multiple stores and feed their values into this pure function and use result of this in rendering. This is not enough if you want to reuse this in more than one component which are not is child-parent relationship(can be passed as props) or if you don't want to expose this dependency between stores inside rendering and have it outside. With little bit of effort this abstraction can be implemented that derivated data for components will look like store and components can reed them and listen on it. From dispacher point of view after he run action through stores he will recalculate derivated data and only after that will issue change events to component. For performace reason you can use imutable data and caching results of derivated functions.
AFAIK NuclearJS solves this with the concept of Getters.
I don't want to complicate Redux with first-class support for derived data, but it's nice to consider options. Ideally I want something like this as a plugin for Redux. (It could come with a custom Injector
that binds to a specific “getter”.)
There's no implementation plans at this point, but I'd love to discuss this and see your ideas!
The ES6 support for Flow seems to have improved quite a bit. Not sure if it covers every feature we're currently using (e.g. the bind operator), but it may be worth giving up a few niceties in exchange for type checking.
https://github.com/facebook/flow/blob/master/Changelog.md#v0120
If using loose mode with babel, composeStores
trips up on __esModule:true
.
First of all, I love this library and the patterns you guys are using. 👍👍
I'm trying to use redux to build an isomorphic app. It's working beautifully so far, except that I need to figure out how to wait until my stores have loaded (on the server) before returning the initial page load. Ideally, the loading should take place in the stores themselves, but when I call dispatch(userActions.load())
, the store has to return the new state (i.e. return { ...state, loading: true };
), so it can't return a promise to wait for. dispatch()
returns the action passed to it for some reason. I'd really like something like...
dispatch(someAsyncAction, successAction, failureAction) => Promise
...where the promise doesn't resolve until one of the other two actions is dispatched.
Is that the sort of thing that could be enabled with the middleware pattern?
Am I totally off base and there's a simple way to do this already?
Thanks.
I haven't given much attention to library size or dependencies yet, as we're still figuring out the right API. However, as people start to depend on it, it's a good idea to check whether we're dragging unnecessary polyfills (babel-runtime?) when it's easily avoidable, and whether there's something we could do to reduce the library size (we can start by adding a UMD build and measuring it! ;-)
I'm currently busy but I'd be happy to see somebody investigate this. If you decide to do it, please let us know in this issue!
I can't pinpoint exactly what is needed for this to happen (I have a pretty complicated setup at the moment), but in some cases I'm getting “This probably means the DOM was unexpectedly mutated” invariant violation on hot reload.
It seems related to hot reloading calling forceUpdate
, which in turn causes Provider#componentWillReceiveProps
, dispatcher replacing, and setState
on the Connector
components below in the tree that receive a new select
prop.
The simple fix is to put a setTimeout
when receiving a new dispatcher in Provider
:
if (redux !== nextRedux) {
setTimeout(() => {
const nextDispatcher = nextRedux.getDispatcher();
redux.replaceDispatcher(nextDispatcher);
});
}
I'm not a fan of this solution so I'll just leave this here for posterity and try to figure out the root issue later. Might be a React bug after all.
When #6 is done, I want to use it to implement hooks for debugging and time travelling from console.
The API could be something like
ReduxDebug.printLastActions();
ReduxDebug.printLastStates();
ReduxDebug.jumpTo(stateId);
etc.
redux is great concept for flux implement.
from now, the redux use high order function to reduce the complexation of decouple between react component / action / store.
redux should to support and how to reuse the existed react components ?
I liked previous decorator. While container
is acceptable, root
is too broad.
Maybe you (@gaearon) could rename root
to provides
or something similar.
Any thoughts?
Waiting until component tests are in place before adding new features, but this will be a simple change.
I'm currently working on some apps that use React Native. Since this Flux lib really reflects my needs and taste for what I want to do, I would like Redux to be usable in React Native as well. Currently it has a hard dependency on React-web. I believe a similar approach to what's done with Flummox is possible here.
What do you think? I can dive into this in a PR if you decide is good to go but not have enough time to do this.
Reviving musings from #6, I'm going to post my progress on working on time travel & other devtool goodness here.
I have a working proof of concept of time travel that uses the default dispatcher and relies on store composition to keep a log of state. This is not feature-complete (only “jumping to state #N” is supported), but shows how to implement such functionality with Store composition:
export const StateKeys = {
LOG: Symbol('Log')
};
export const ActionTypes = {
JUMP_TO_STATE: Symbol('JUMP_TO_STATE')
};
export default function recorder(store) {
return function Recorder(state = {}, action) {
let { [StateKeys.LOG]: log = [], ...atom } = state;
let nextAtom;
switch (action.type) {
case ActionTypes.JUMP_TO_STATE:
const { index } = action;
nextAtom = log[index].nextAtom;
break;
default:
nextAtom = store(atom, action);
break;
}
log = [...log, {
action,
atom,
nextAtom
}];
return {
[StateKeys.LOG]: log,
...nextAtom
};
}
}
Usage:
const store = composeStores(stores);
const dispatcher = createDispatcher(recorder(store)); // wrap the store
const redux = createRedux(dispatcher);
This relies on the root atom being “normal” a JS object though. I think we'll need to store it internally as atom
field instead inside a plain JS object created by us to support such “hidden” tool state.
I'd accept a PR that hides the user store's state inside an atom
field on the Redux instance's state
object, at the same time preserving the current API and behavior exactly. Redux.getState()
should keep retuning that atom. Any other fields on the internal state
will be assumed to be only used by the devtools.
In the example app, incrementIfOdd
breaks after the first hot reload. getState
seems to return the initial state rather than the current state.
I'll get straight to it, will dive into more details if you need.
boring example 1 - local state
class Counter{
render(){
return <State initial={0}>{
(val, set) =>
<div onClick={() => set(val + 1)}>
clicked {val} times
</div>
}</State>;
}
}
all state changes with set()
will not be reflected while replaying, BUT because it's 'local', you'd still 'start' and 'end' at the correct states.
boring example 2, spring animations
<Spring to={10}>
{val => <div>{val}</div>}
</Spring>
this works fine! it might be dicey if you use onSpringUpdate
to update something globally AND your timer goes out of sync. Didn't see it happen with simple examples.
boring example 3
<Ajax url='my/ajax/url'>{
{results => !results ? 'loading...' : `fetched ${results.length} results`}
}</Ajax>
this is tricky. lets say while recording, the request took 2 seconds, and on the 3rd second you did something to change global state based on this. then when replaying, if the request takes 5 seconds, then Putin conquers your apartment with babooshkas. (this is a similar problem to firing ajax requests in stores and trying to do record/replay)
So yeah, it's obvious that issues like this would come up, because 'replay flux' requires state to be managed centrally. That said, this is better than I expected, and I'm happy to recognize the limitations.
cheers!
I think Function.prototype.toString()
smells isn't good
When specifying Container
or @container
, the name under which the store is exported is insignificant. You just assign it a string key:
@container({
stores: { counter: counterStore }
})
and it appears as counter
.
There is now a single place where it's still significant: the action creator callback form.
export function incrementIfOdd() {
return (dispatch, state) => {
if (state.counterStore % 2 === 0) { // reading from counterStore state here
return;
}
dispatch(increment());
};
}
It's not obvious that it's called counterStore
because of export { default as counterStore } from './counterStore
inside stores/index.js
passed to the @root
.
An alternative is to let state
be ES6 map with Store functions as keys. Then you'd do
import counterStore from './stores/counterStore';
export function incrementIfOdd() {
return (dispatch, state) => {
if (state.get(counterStore) % 2 === 0) { // get state for the store
return;
}
dispatch(increment());
};
}
This code won't break if you rename the export, and also makes the dependency clear.
Thoughts?
A lot of problems were solved in 0.3 rewrite but unfortunately the Store function name is now significant. It is used as the key to the related state partition. Because Stores are not registered anywhere, there are a couple of weird problems:
We can't rely on the function identity because of hot reloading. The same Store will he represented by different functions over time.
I feel this calls for a "Store registry" where you'd assign a unique key to each Store. I can't pinpoint the API yet so let's leave this open. If you have suggestions please let me know.
As rightly noted by @vslinko, it's better to provide getState
instead of initialState
.
I think I was wrong now when I said this. In fact, I find it now easier to implement composable dispatchers only if each “parent” has the ability to “intercept” both getState
and setState
, and if the child can “query” the latest state.
I'm going to keep this open for a while, as I'm still not 100% sure which approach is more correct, but I'm leaning towards (getState, setState) => action => ()
now as the signature for the dispatcher.
Following @DenisIzmaylov's suggestion in #95, I propose we adopt the Airbnb styleguide and change the style if it differs from Airbnb.
If everyone's on board with this, I'd accept a PR that:
.eslintrc
as possibleThoughts?
Currently many branches are untested.
See for yourself:
git clone https://github.com/gaearon/redux.git
cd redux
npm install
npm run test:cov
Here's what I see:
=============================== Coverage summary ===============================
Statements : 93.18% ( 328/352 )
Branches : 51.72% ( 30/58 )
Functions : 95.24% ( 60/63 )
Lines : 93.16% ( 327/351 )
================================================================================
You can inspect particular untested branches by running
open coverage/lcov-report/index.html
Here's an example of the behavior we should add tests for:
If you'd like to volunteer to help with adding the missing tests, please write in this issue.
Need to look into this. That's because the decorator is reevaluated and the returned component type is different. This isn't a problem when using vanilla container components.
Hi there,
reading the Readme.md
file I see the incrementIfOdd
function defined there BUT I cannot make up how to use it and it seems to be not used in the example either - should these actions just be passed as actions
to the <Container ...>
as well, like this...?
export default class CounterContainer {
render() {
// stores can be a single store or an array.
// actions can only be a string -> function map.
// props passed to children will combine these actions and state.
return (
<Container stores={counterStore}
actions={{ increment, decrement, incrementIfOdd }}>
{props => <Counter {...props} />}
</Container>
);
}
}
Thanks a lot in advance :)
PS: Thanks for starting this new flux implementation - the work you and the awesome contributors have done so far is really inspirational :)
Few things:
First one: Why this? https://github.com/gaearon/redux/blob/master/src/components/Connector.js#L19 - not sure whether "flux" lib should cream about this part.
Second one: due to custom method shouldComponentUpdate "rerendering" of component does not work.
Look at my code:
Inside container component:
<Connector select={select}>
{({ userFooter, dispatcher }) =>
<UserFooter userFooter={userFooter} {...bindActions(UserActions, dispatcher)} />
}
</Connector>
select method:
let select = (state) => {
return {
userFooter: state.userFooter
}
}
Store:
const initialState = {
isAuthenticated: false,
email: ''
}
let setAuthenticated = (state) => {
state.isAuthenticated = false
state.email = ''
return state
}
export default createStore(initialState, {
[LOGIN_SUCCESS]: (state, action) => {
state.isAuthenticated = true
state.email = action.email
return state
},
[LOGIN_FAILURE]: (state, action) => {
return setAuthenticated(state)
},
[LOGOUT]: (state, action) => {
return setAuthenticated(state)
}
})
Then state.isAuthenticated will change to false. But Connector component does not render component "UserFooter" inside.
UserFooter component:
export default (React) => {
let types = React.PropTypes
let UserFooter = (props) => {
console.log('props', props)
return {
__proto__: React.Component.prototype,
props,
logout (e) {
e.preventDefault()
this.props.logout()
},
render () {
let {isAuthenticated, email} = this.props.userFooter
console.log('render', isAuthenticated)
return (
<div>
{isAuthenticated ? (
<p>
Logged as : {email}
<br/>
<a onClick={(e) => this.logout(e) }>Sign Out</a>
</p>
) : (
<Link to='login'>Sign In</Link>
)}
</div>
)
}
}
}
UserFooter.propTypes = {
// isAuthenticated: types.bool.isRequired,
// email: types.string,
userFooter: types.object.isRequired,
logout: types.func.isRequired
}
return UserFooter
}
Last thing: Amazing work mate!
Following the directions:
git clone https://github.com/gaearon/redux.git redux
cd redux
npm install
npm start
The example app loads/works fine, but changes to the example files don't seem to cause a hot reload.
Can anyone else confirm this?
Thanks!
I've heard from several people they already want to use this in production, which is a pretty crazy idea, if you ask me 😉 . Still, it's better to consider production use cases early. One of such use cases is code splitting.
Large apps don't want to carry all the code in one JS bundle. Webpack and Browserify allow you to split your app into several parts. One core part loads first, the rest is loaded on demand. We want to support this.
Currently Redux forces you to declare all Stores at the root. This is sensible because if you register them lazily as components subscribe to them, some Stores might miss some actions. This is totally not obvious and fragile.
However, defining all Stores at the root robs us of some of the benefits of code splitting, as all Stores will have to be included in the application's entry point bundle.
So here's my proposal. (I haven't thought it through at all; tell me if it's silly.)
I want to support several <Root>
s throughout the application. Whenever a new <Root>
is mounted under an existing one, instead of initializing a new dispatcher, it adds its stores
to the parent dispatcher. They do not receive the actions they missed—fair game IMO.
Open questions:
<Root>
unmounts?stores
prop?<Root>
to something like <Dispatcher>
?I don't know if it's a good design or not, just something to get the ball rolling.
I want to have some consistent state lifecycle story that works with big apps.
I don't like this idea. If the code loads, it should start handling the actions immediately; not when some view mounts. And what if the new view mounts, and then unmounts? Its <Root>
will be gone, poof! But we don't want to erase its state.
Perhaps, a better idea is to rely on React! We got <Root>
at the top. (Yo, let's call it <Dispatcher>
;-). Okay, so we got <Dispatcher>
at the top. And it has a stores
prop. (Not in the decorator version, but we're looking at an advanced use case.) And we got React. And React lets you change props. Get it?
// ------
// Core App
// ------
// StoreRegistry.js
let allStores = {};
let emitChange = null;
export function register(newStores) {
allStores = { ...allStores, ...newStores }
emitChange(allStores);
}
export function setChangeListener(listener) {
if (emitChange) throw new Error('Can set listener once.'); // lol
emitChange = listener;
emitChange(allStores);
}
// App.js
import { Dispatcher } from 'redux';
import * as StoreRegistry form './stores/registry';
import * as coreStores from './stores/core';
StoreRegistry.register(coreStores);
class App extends Component {
constructor(props) {
super(props);
StoreRegistry.setChangeListener(() => this.handleStoresChange);
}
handleStoresChange(stores) {
if (this.state) {
this.setState({ stores });
} else {
this.state = { stores };
}
}
render() {
return (
<Dispatcher stores={this.state.stores}>
<SomeRootView />
</Dispatcher>
);
}
}
// ------
// Dynamic module loaded with code splitting
// ------
import * as StoreRegistry form './stores/registry';
import * as extraStores from './stores/extraStores';
// Boom! Will register code-splitted stores.
StoreRegistry.register(extraStores);
// Note that we want to register them when the code loads, not when view mounts.
// The view may never mount, but we want them to start listening to actions ASAP.
// Their state is never destroyed (consistent with the code never being unloaded).
Thoughts?
cc @vslinko
export default async function renderPage(url) {
const dispatcher = createDispatcher(composeStores(stores))
const {title} = await dispatcher.perform(runTransition(url))
// I need to get atom to make some checks
const {atom} = dispatcher.dehydrate()
if (!atom.routerStore.componentKey) {
return {
status: 404
}
}
// But after that checks I should return atom into dispatcher for render usages
// I want to remove this step
dispatcher.hydrate({atom})
const pageContent = React.renderToString(
<Provider dispatcher={dispatcher}>
{() => <Application dispatcher={dispatcher} />}
</Provider>
)
return {
body: appTemplate(title, pageContent, atom)
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.