49 | {lastUpdated && 50 | 51 | Last updated at {new Date(lastUpdated).toLocaleTimeString()}. 52 | {' '} 53 | 54 | } 55 | {!isFetching && 56 | 58 | Refresh 59 | 60 | } 61 |
62 | {isEmpty 63 | ? (isFetching ?10 | Clicked: 0 times 11 | 12 | 13 | 14 | 15 |
16 |24 | Clicked: {value} times 25 | {' '} 26 | 29 | {' '} 30 | 33 | {' '} 34 | 37 | {' '} 38 | 41 |
42 | ) 43 | } 44 | } 45 | 46 | export default Counter 47 | -------------------------------------------------------------------------------- /examples/counter/src/components/Counter.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { shallow } from 'enzyme' 3 | import Counter from './Counter' 4 | 5 | function setup(value = 0) { 6 | const actions = { 7 | onIncrement: jest.fn(), 8 | onDecrement: jest.fn() 9 | } 10 | const component = shallow( 11 |Type a username or repo full name and hit 'Go':
42 | 46 | 49 |50 | Code on Github. 51 |
52 |53 | Move the DevTools with Ctrl+W or hide them with Ctrl+H. 54 |
55 |{description}
21 | } 22 |34 | {errorMessage} 35 | {' '} 36 | ( 38 | Dismiss 39 | ) 40 |
41 | ) 42 | } 43 | 44 | render() { 45 | const { children, inputValue } = this.props 46 | return ( 47 |Total: ${total}
24 | 28 |
7 | Show:
8 | {" "}
9 |
6 | Show:
7 | {" "}
8 |
7 | 10 | 13 |
14 | ) 15 | 16 | const mapStateToProps = (state) => ({ 17 | canUndo: state.todos.past.length > 0, 18 | canRedo: state.todos.future.length > 0 19 | }) 20 | 21 | const mapDispatchToProps = ({ 22 | onUndo: UndoActionCreators.undo, 23 | onRedo: UndoActionCreators.redo 24 | }) 25 | 26 | UndoRedo = connect( 27 | mapStateToProps, 28 | mapDispatchToProps 29 | )(UndoRedo) 30 | 31 | export default UndoRedo 32 | -------------------------------------------------------------------------------- /examples/todos-with-undo/src/containers/VisibleTodoList.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux' 2 | import { toggleTodo } from '../actions' 3 | import TodoList from '../components/TodoList' 4 | 5 | const getVisibleTodos = (todos, filter) => { 6 | switch (filter) { 7 | case 'SHOW_ALL': 8 | return todos 9 | case 'SHOW_COMPLETED': 10 | return todos.filter(t => t.completed) 11 | case 'SHOW_ACTIVE': 12 | return todos.filter(t => !t.completed) 13 | default: 14 | throw new Error('Unknown filter: ' + filter) 15 | } 16 | } 17 | 18 | const mapStateToProps = (state) => ({ 19 | todos: getVisibleTodos(state.todos.present, state.visibilityFilter) 20 | }) 21 | 22 | const mapDispatchToProps = ({ 23 | onTodoClick: toggleTodo 24 | }) 25 | 26 | const VisibleTodoList = connect( 27 | mapStateToProps, 28 | mapDispatchToProps 29 | )(TodoList) 30 | 31 | export default VisibleTodoList 32 | -------------------------------------------------------------------------------- /examples/todos-with-undo/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import { createStore } from 'redux' 4 | import { Provider } from 'react-redux' 5 | import App from './components/App' 6 | import reducer from './reducers' 7 | 8 | const store = createStore(reducer) 9 | 10 | render( 11 |
6 | Show:
7 | {" "}
8 |
5 | Clicked: {counter} times 6 | {' '} 7 | 8 | {' '} 9 | 10 | {' '} 11 | 12 | {' '} 13 | 14 |
15 | ) 16 | 17 | Counter.propTypes = { 18 | increment: PropTypes.func.isRequired, 19 | incrementIfOdd: PropTypes.func.isRequired, 20 | incrementAsync: PropTypes.func.isRequired, 21 | decrement: PropTypes.func.isRequired, 22 | counter: PropTypes.number.isRequired 23 | } 24 | 25 | export default Counter 26 | -------------------------------------------------------------------------------- /examples/universal/common/containers/App.js: -------------------------------------------------------------------------------- 1 | import { bindActionCreators } from 'redux' 2 | import { connect } from 'react-redux' 3 | import Counter from '../components/Counter' 4 | import * as CounterActions from '../actions' 5 | 6 | const mapStateToProps = (state) => ({ 7 | counter: state.counter 8 | }) 9 | 10 | function mapDispatchToProps(dispatch) { 11 | return bindActionCreators(CounterActions, dispatch) 12 | } 13 | 14 | export default connect(mapStateToProps, mapDispatchToProps)(Counter) 15 | -------------------------------------------------------------------------------- /examples/universal/common/reducers/counter.js: -------------------------------------------------------------------------------- 1 | import { SET_COUNTER, INCREMENT_COUNTER, DECREMENT_COUNTER } from '../actions' 2 | 3 | const counter = (state = 0, action) => { 4 | switch (action.type) { 5 | case SET_COUNTER: 6 | return action.payload 7 | case INCREMENT_COUNTER: 8 | return state + 1 9 | case DECREMENT_COUNTER: 10 | return state - 1 11 | default: 12 | return state 13 | } 14 | } 15 | 16 | export default counter 17 | -------------------------------------------------------------------------------- /examples/universal/common/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux' 2 | import counter from './counter' 3 | 4 | const rootReducer = combineReducers({ 5 | counter 6 | }) 7 | 8 | export default rootReducer 9 | -------------------------------------------------------------------------------- /examples/universal/common/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux' 2 | import thunk from 'redux-thunk' 3 | import rootReducer from '../reducers' 4 | 5 | const configureStore = (preloadedState) => { 6 | const store = createStore( 7 | rootReducer, 8 | preloadedState, 9 | applyMiddleware(thunk) 10 | ) 11 | 12 | if (module.hot) { 13 | // Enable Webpack hot module replacement for reducers 14 | module.hot.accept('../reducers', () => { 15 | const nextRootReducer = require('../reducers').default 16 | store.replaceReducer(nextRootReducer) 17 | }) 18 | } 19 | 20 | return store 21 | } 22 | 23 | export default configureStore 24 | -------------------------------------------------------------------------------- /examples/universal/index.js: -------------------------------------------------------------------------------- 1 | require('./client') 2 | -------------------------------------------------------------------------------- /examples/universal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redux-universal-example", 3 | "version": "0.0.0", 4 | "description": "An example of a universally-rendered Redux application", 5 | "scripts": { 6 | "start": "node server/index.js" 7 | }, 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/reactjs/redux.git" 11 | }, 12 | "license": "MIT", 13 | "bugs": { 14 | "url": "https://github.com/reactjs/redux/issues" 15 | }, 16 | "homepage": "http://redux.js.org", 17 | "dependencies": { 18 | "babel-polyfill": "^6.3.14", 19 | "babel-register": "^6.4.3", 20 | "express": "^4.13.3", 21 | "qs": "^4.0.0", 22 | "react": "^0.14.7", 23 | "react-dom": "^0.14.7", 24 | "react-redux": "^4.2.1", 25 | "redux": "^3.2.1", 26 | "redux-thunk": "^1.0.3", 27 | "serve-static": "^1.10.0" 28 | }, 29 | "devDependencies": { 30 | "babel-core": "^6.3.15", 31 | "babel-loader": "^6.2.0", 32 | "babel-preset-es2015": "^6.3.13", 33 | "babel-preset-react": "^6.3.13", 34 | "babel-preset-react-hmre": "^1.1.1", 35 | "babel-runtime": "^6.3.13", 36 | "webpack": "^1.11.0", 37 | "webpack-dev-middleware": "^1.4.0", 38 | "webpack-hot-middleware": "^2.9.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /examples/universal/server/index.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | require('./server') 3 | -------------------------------------------------------------------------------- /examples/universal/server/server.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console, no-use-before-define */ 2 | 3 | import path from 'path' 4 | import Express from 'express' 5 | import qs from 'qs' 6 | 7 | import webpack from 'webpack' 8 | import webpackDevMiddleware from 'webpack-dev-middleware' 9 | import webpackHotMiddleware from 'webpack-hot-middleware' 10 | import webpackConfig from '../webpack.config' 11 | 12 | import React from 'react' 13 | import { renderToString } from 'react-dom/server' 14 | import { Provider } from 'react-redux' 15 | 16 | import configureStore from '../common/store/configureStore' 17 | import App from '../common/containers/App' 18 | import { fetchCounter } from '../common/api/counter' 19 | 20 | const app = new Express() 21 | const port = 3000 22 | 23 | // Use this middleware to set up hot module reloading via webpack. 24 | const compiler = webpack(webpackConfig) 25 | app.use(webpackDevMiddleware(compiler, { noInfo: true, publicPath: webpackConfig.output.publicPath })) 26 | app.use(webpackHotMiddleware(compiler)) 27 | 28 | // This is fired every time the server side receives a request 29 | app.use(handleRender) 30 | 31 | function handleRender(req, res) { 32 | // Query our mock API asynchronously 33 | fetchCounter(apiResult => { 34 | // Read the counter from the request, if provided 35 | const params = qs.parse(req.query) 36 | const counter = parseInt(params.counter, 10) || apiResult || 0 37 | 38 | // Compile an initial state 39 | const preloadedState = { counter } 40 | 41 | // Create a new Redux store instance 42 | const store = configureStore(preloadedState) 43 | 44 | // Render the component to a string 45 | const html = renderToString( 46 | extends ReduxAction {
6 | payload: P;
7 | }
8 |
9 | const action: Action {
11 | , getState: () => S) => R): R;
12 | }
13 | }
14 |
15 | const dispatchThunkResult: number = dispatch(() => 42);
16 | const dispatchedTimerId: number = dispatch(d => setTimeout(() => d({type: 'TYPE'}), 1000));
17 |
--------------------------------------------------------------------------------
/test/typescript/middleware.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Middleware, MiddlewareAPI,
3 | applyMiddleware, createStore, Dispatch, Reducer, Action
4 | } from "../../index.d.ts";
5 |
6 | declare module "../../index.d.ts" {
7 | export interface Dispatch {
8 | , getState: () => S) => R): R;
9 | }
10 | }
11 |
12 | type Thunk = (dispatch: Dispatch, getState: () => S) => O;
13 |
14 | const thunkMiddleware: Middleware =
15 | ({dispatch, getState}: MiddlewareAPI) =>
16 | (next: Dispatch) =>
17 | (action: A | Thunk): B|Action =>
18 | typeof action === 'function' ?
19 | (({getState}: MiddlewareAPI) =>
25 | (next: Dispatch) =>
26 | (action: any): any => {
27 | console.log('will dispatch', action)
28 |
29 | // Call the next dispatch method in the middleware chain.
30 | const returnValue = next(action)
31 |
32 | console.log('state after dispatch', getState())
33 |
34 | // This will likely be the action itself, unless
35 | // a middleware further in chain changed it.
36 | return returnValue
37 | }
38 |
39 |
40 |
41 | type State = {
42 | todos: string[];
43 | }
44 |
45 | const reducer: Reducer(next: StoreEnhancerStoreCreator) => next;
25 | const specificEnhencer: StoreEnhancer