├── .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 |
8 | {
9 | this.props.todos.map((todo)=>{
10 | return - {todo.text}
11 | })
12 | }
13 |
14 |
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 |
--------------------------------------------------------------------------------