├── .eslintrc ├── .gitignore ├── README.md ├── client ├── client.js └── index.html ├── components ├── App.js ├── TodoInput.js └── TodoList.js ├── package.json ├── redux ├── actions.js ├── reducer.js └── store.js ├── server └── server.js └── webpack.config.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "env": { 4 | "browser": true, 5 | "node": true 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | dist/ 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React-redux 2 | 3 | 4 | You might start with master branch. 5 | 6 | After you master the master branch,than head to the toggle branch. 7 | 8 | It's the step order of branchs. 9 | ``` 10 | 1.master 11 | 2.toggle 12 | 3.link 13 | 4.combindReducer 14 | 5.ajax 15 | 6.react-redux-router 16 | ``` 17 | -------------------------------------------------------------------------------- /client/client.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import App from '../components/App' 4 | import configureStore from '../redux/store' 5 | import {Provider} from 'react-redux' 6 | 7 | let initialState = { 8 | todos:[{ 9 | id:0, 10 | completed: false, 11 | text:'initial for demo' 12 | 13 | }] 14 | } 15 | let store = configureStore(initialState); 16 | 17 | render( 18 | 19 | 20 | , 21 | document.getElementById('app') 22 | ) 23 | -------------------------------------------------------------------------------- /client/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React Todo List 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /components/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import TodoInput from './TodoInput.js' 3 | import TodoList from './TodoList.js' 4 | import {connect} from 'react-redux' 5 | class App extends Component { 6 | 7 | render() { 8 | return ( 9 |
10 |

Todo list

11 | 12 | 13 |
14 | ) 15 | } 16 | 17 | } 18 | function mapStateToProps(state){ 19 | 20 | return state 21 | } 22 | 23 | 24 | export default connect(mapStateToProps)(App) 25 | -------------------------------------------------------------------------------- /components/TodoInput.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import action from '../redux/actions.js' 3 | class TodoInput extends Component { 4 | 5 | constructor(props, context) { 6 | super(props, context) 7 | this.state = { 8 | inputText: '' 9 | } 10 | this.handleSubmit = this.handleSubmit.bind(this); 11 | } 12 | 13 | 14 | handleChange(event) { 15 | this.setState({ 16 | inputText: event.target.value 17 | }) 18 | } 19 | handleSubmit(){ 20 | event.preventDefault() 21 | //this.props.dispatch() 22 | this.props.dispatch(action.addTodo(this.state.inputText)); 23 | } 24 | 25 | 26 | 27 | 28 | render() { 29 | return ( 30 |
31 | 37 | 38 |
39 | ) 40 | } 41 | 42 | } 43 | 44 | export default TodoInput 45 | -------------------------------------------------------------------------------- /components/TodoList.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | 3 | class TodoList extends Component { 4 | 5 | render() { 6 | return ( 7 | 15 | ) 16 | } 17 | 18 | } 19 | 20 | export default TodoList 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-todo-list", 3 | "version": "1.0.0", 4 | "description": "A simple todo list app built with React, Redux and Webpack", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "serve": "nodemon server/server.js --ignore components" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/kweiberth/react-todo-list.git" 12 | }, 13 | "author": "Kurt Weiberth", 14 | "license": "ISC", 15 | "dependencies": { 16 | "babel-core": "^6.4.5", 17 | "babel-loader": "^6.2.2", 18 | "babel-preset-es2015": "^6.3.13", 19 | "babel-preset-react": "^6.3.13", 20 | "babel-preset-react-hmre": "^1.1.0", 21 | "express": "^4.13.4", 22 | "react": "^0.14.7", 23 | "react-dom": "^0.14.7", 24 | "react-redux": "^4.4.5", 25 | "redux": "^3.6.0", 26 | "redux-logger": "^2.6.1", 27 | "webpack": "^1.12.13", 28 | "webpack-dev-middleware": "^1.5.1", 29 | "webpack-hot-middleware": "^2.6.4" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /redux/actions.js: -------------------------------------------------------------------------------- 1 | let actions ={ 2 | addTodo:(text)=>{ 3 | return ({ 4 | type:'ADD_TODO', 5 | text:text}) 6 | } 7 | } 8 | 9 | 10 | export default actions -------------------------------------------------------------------------------- /redux/reducer.js: -------------------------------------------------------------------------------- 1 | function getId(state){ 2 | return state.todos.reduce((maxId,todo)=>{ 3 | return Math.max(todo.id,maxId) 4 | },-1) + 1 5 | 6 | } 7 | 8 | 9 | export default function reducer(state,action){ 10 | switch(action.type){ 11 | case 'ADD_TODO': 12 | 13 | return( Object.assign({},state,{ 14 | todos:[{ 15 | text:action.text, 16 | completed:false, 17 | id:getId(state) 18 | 19 | },...state.todos] 20 | }) 21 | ) 22 | default: 23 | return state; 24 | 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /redux/store.js: -------------------------------------------------------------------------------- 1 | import {applyMiddleware,compose,createStore} from "redux" 2 | import reducer from './reducer' 3 | import logger from 'redux-logger' 4 | 5 | let finalCreateStore = compose( 6 | applyMiddleware(logger()) 7 | )(createStore) 8 | 9 | export default function configureStore(initialState = { todos:[]}){ 10 | return finalCreateStore(reducer,initialState) 11 | 12 | } -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var config = require('../webpack.config.js'); 4 | var webpack = require('webpack'); 5 | var webpackDevMiddleware = require('webpack-dev-middleware'); 6 | var webpackHotMiddleware = require('webpack-hot-middleware'); 7 | 8 | var app = express(); 9 | 10 | var compiler = webpack(config); 11 | 12 | app.use(webpackDevMiddleware(compiler, {noInfo: true, publicPath: config.output.publicPath})); 13 | app.use(webpackHotMiddleware(compiler)); 14 | 15 | app.use(express.static('./dist')); 16 | 17 | app.use('/', function (req, res) { 18 | res.sendFile(path.resolve('client/index.html')); 19 | }); 20 | 21 | var port = 3000; 22 | 23 | app.listen(port, function(error) { 24 | if (error) throw error; 25 | console.log("Express server listening on port", port); 26 | }); 27 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack'); 2 | 3 | module.exports = { 4 | devtool: 'inline-source-map', 5 | entry: [ 6 | 'webpack-hot-middleware/client', 7 | './client/client.js' 8 | ], 9 | output: { 10 | path: require("path").resolve("./dist"), 11 | filename: 'bundle.js', 12 | publicPath: '/' 13 | }, 14 | plugins: [ 15 | new webpack.optimize.OccurrenceOrderPlugin(), 16 | new webpack.HotModuleReplacementPlugin(), 17 | new webpack.NoErrorsPlugin() 18 | ], 19 | module: { 20 | loaders: [ 21 | { 22 | test: /\.js$/, 23 | loader: 'babel-loader', 24 | exclude: /node_modules/, 25 | query: { 26 | presets: ['react', 'es2015', 'react-hmre'] 27 | } 28 | } 29 | ] 30 | } 31 | } 32 | --------------------------------------------------------------------------------