媒介
近來一直在進修react手藝棧,相干的理論和觀點基礎都了解了,之前也用reactjs寫了幾個demo,切身體會到了函數式編程和組件化開闢的壯大的處所,但因種種主客觀緣由,預先沒有對相干知識點舉行梳理和總結,而且事情中也沒用到,致使如今溫習的時刻陌生了,還須要花大部分時候從新理清需乞降邏輯,做了許多重複性的事情,太得不償失了。為了進步本身的進修效力,防止做一些無用的事情,我也決議今後(無論是事情照樣進修)一定要養成定時總結的習氣,而且也要用筆墨紀錄下來,如許能夠經常溫習,理清邏輯,加深印象。別的,關於我個人的進修總結,若有不對的處所,迎接批評指正,期待共同進步!不喜勿噴,感謝!
第一章 頁面搭建
目次構造
├── components
| └──app.css//款式文件
├── node_modules //依靠包
├── static //靜態文件
| └──index.html //進口html文件
| └──bundle.js //編譯后的js文件
├── index.js //主進口js文件
├── package.json //項目所依靠的npm包
├── webpack.config.js //webpack配置文件
└── yarn.lock //依靠或許更新包相干版本信息。如許能夠處置懲罰同一個項目在差別机械上環境不一致的題目。
包治理文件 package.json
{
"name": "todolist",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack",
"start": "webpack-dev-server --line --hot",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "www.icrazyman.cn",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.21.0",
"babel-loader": "^6.2.10",
"babel-preset-es2015": "^6.18.0",
"babel-preset-react": "^6.16.0",
"css-loader": "^0.28.4",
"react": "^15.4.1",
"react-dom": "^15.4.1",
"style-loader": "^0.18.2",
"webpack": "^1.14.0",
"webpack-dev-server": "^1.16.2"
},
"dependencies": {
"node": "^6.11.1"
}
}
進口文件index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Redux Todos Example</title>
</head>
<body>
<div class="todoapp" id="root"></div>
<script src="bundle.js"></script>
</body>
</html>
index.js
import第三方依靠包和css文件
import React from 'react'
import { render } from 'react-dom'
import './components/app.css'
render(
<div className='todo-box'>
<div className='todo-innerBox'>
<div className='todo-tab'>
<div className='todo-tab_item'>
<a href='javascript:;'>悉數使命</a>
</div>
<div className='todo-tab_item'>
<a href='javascript:;'>待辦使命</a>
</div>
<div className='todo-tab_item'>
<a href='javascript:;'>已完成使命</a>
</div>
</div>
<ul className='list-group'>
<li className="todo-list_li">
<input type="checkbox" className="pull-left" value="on" />
aaa
</li>
<li className="todo-list_li">
<input type="checkbox" className="pull-left" value="on" />
bbb
</li>
<li className="todo-list_li">
<input type="checkbox" className="pull-left" value="on" />
ccc
</li>
</ul>
<div>
<form>
<input placeholder='你想做點什麼' className='todo-input' />
<button type='submit' className='todo-btn'>增加使命</button>
</form>
</div>
</div>
</div>,
document.getElementById('root')
)
webpack配置文件webpack.config.js
module.exports = {
devtool: 'eval-source-map', //挑選map來加強調試歷程
entry: __dirname + '/index.js', //進口文件
output: {
path: __dirname + '/static',//打包天生途徑
filename: 'bundle.js'
},
module: {
loaders: [{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
}, { test: /\.css$/, loader: 'style-loader!css-loader' }]
},
devServer: { //熱更新
contentBase: './static',
historyApiFallback: true,
inline: true,
hot: true
}
}
翻開終端運轉yarn
或npm install
裝置依靠,運轉npm run build
編譯,運轉npm start
舉行檢察頁面是不是一般顯現
小結:這個階段只是把頁面完成出來了,還沒有完成任何邏輯。个中頁面完成的步驟為:
1. 在index.html編寫html構造和css款式
2. 把html構造提取到index.js組件中同時轉換成jsx語法
3. 把css款式提取到app.css中
第二章 引入redux組件化
目次構造
├── actions
| └──index.js//治理狀況
├── components
| └──app.css//款式文件
| └──App.js//UI組件進口文件
| └──Link.js//UI組件
| └──Todo.js//UI組件
| └──Top.js//UI組件
├── containers
| └──VisibleTodoList.js//容器組件
| └──AddTodo.js//容器組件
| └──FilterLink.js//容器組件
├── reducers
| └──index.js//數據邏輯處置懲罰文件
├── node_modules //依靠包
├── static //靜態文件
| └──index.html //進口html文件
| └──bundle.js //編譯后的js文件
├── index.js //主進口js文件
├── package.json //項目所依靠的npm包
├── webpack.config.js //webpack配置文件
└── yarn.lock //依靠或許更新包相干版本信息。如許能夠處置懲罰同一個項目在差別机械上環境不一致的題目。
裝置依靠包
此次新增react-redux和redux依靠包
{
"name": "todolist",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack",
"start": "webpack-dev-server --line --hot",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.21.0",
"babel-loader": "^6.2.10",
"babel-preset-es2015": "^6.18.0",
"babel-preset-react": "^6.16.0",
"css-loader": "^0.28.4",
"react": "^15.4.1",
"react-dom": "^15.4.1",
"react-redux": "^5.0.1",
"redux": "^3.6.0",
"style-loader": "^0.18.2",
"webpack": "^1.14.0",
"webpack-dev-server": "^1.16.2"
},
"dependencies": {
"node": "^6.11.1"
}
}
index.js
此次應用redux治理全部項目的狀況,而且把項目代碼抽離成組件
//注重:import后不加{}代表引入的default,加了{}代表引入个中導出的一部分,用到了ES6的解構
//注重:import后不加{}代表引入的default,加了{}代表引入个中導出的一部分,用到了ES6的解構
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
import { createStore } from 'redux'
//數據邏輯處置懲罰保存在reducers里
import todoApp from './reducers'
import App from './components/App'
//在頂層豎立store治理全部項目的數據
const store = createStore(todoApp)
console.log('9. root index start')
//connect要領天生容器組件今後,須要讓容器組件拿到state對象,才天生 UI 組件的參數。
// 一種處置懲罰要領是將state對象作為參數,傳入容器組件。然則,如許做比較貧苦,尤其是容器組件可能在很深的層級,一級級將state傳下去就很貧苦。
// React-Redux 供應Provider組件,能夠讓容器組件拿到state。
//Provider在根組件表面包了一層,如許一來,App的一切子組件就默許都能夠拿到state了。
render(
<Provider store={store}>
<App />
</Provider>
,document.getElementById('root')
)
console.log('9. root index end')
reducers/index.js
把數據邏輯處置懲罰的代碼抽離成reducers
import { combineReducers } from 'redux'
console.log('data flow:')
console.log('1. reducers start')
/* 傳入舊的state和作用的action返回一個新state */
const todo = (state, action) => {
console.log('data flow 4')
switch(action.type) {
case 'ADD_TODO':
return {
id: action.id,
text: action.text,
completed: false //新增默許為未完成
}
case 'TOGGLE_TODO':
if (state.id !== action.id) {
return state
}
return Object.assign({}, state, {completed: !state.completed})
default:
return state
}
}
const todos = (state = [], action) => {
console.log('1.1 todos twice')
switch(action.type) {
case 'ADD_TODO':
return [
...state,
todo(undefined, action)
]
//todo(undefined, action) 新增一條紀錄時第一個參數state不存在
case 'TOGGLE_TODO':
return state.map(t => todo(t, action));
default:
return state;
}
}
const visibilityFilter = (state = 'SHOW_ALL', action) => {
console.log('1.2 visibilityFilter twice')
switch (action.type) {
case 'SET_VISIBILITY':
return action.filter;
default:
return state;
}
}
console.log('1. reducers end')
export default combineReducers({
todos,
visibilityFilter
});
actions/index.js
在redux中,actions是觸發store中數據更新的唯一泉源,所以要寫個actions應用dispatch要領來觸發store中治理的狀況更新
let nextTodoId = 0;
console.log('2. actions start')
// 增加
const addTodo = (text) => {
// console.log('text:' + text)
console.log('data flow 2')
let id = nextTodoId ++ ;
return {
type: 'ADD_TODO',
id: id,
text
}
}
// 頂部顯現狀況
const setVisibility = (filter) => {
// console.log('filter:' + filter)
return {
type: 'SET_VISIBILITY',
filter
}
}
// 觸發
const toggleTodo = (id) => {
// console.log('id:' + id)
return {
type: 'TOGGLE_TODO',
id
}
}
export {addTodo, setVisibility, toggleTodo}
console.log('2. actions end')
components/App.js
子組件的進口文件,擔任對抽離出的子組件舉行組合然後導出
import React from 'react'
import Top from './Top'
import VisibleTodoList from '../containers/VisibleTodoList'
import AddTodo from '../containers/AddTodo'
import './app.css'
console.log('8. App.js start')
const App = () => (
<div className='todo-box'>
<div className='todo-innerBox'>
<Top />
<VisibleTodoList />
<AddTodo />
</div>
</div>
)
console.log('8. App.js end')
export default App;
components/Top.js
TodoList頂部組件
import React from 'react'
import { connect } from 'react-redux'
import { setVisibility } from '../actions'
import FilterLink from '../containers/FilterLink'
console.log('4. Top.js start')
const Top = () => (
<div className="todo-tab">
<FilterLink filter="SHOW_ALL">
悉數使命
</FilterLink>
<FilterLink filter="SHOW_ACTIVE">
待辦使命
</FilterLink>
<FilterLink filter="SHOW_COMPLETED">
已完成使命
</FilterLink>
</div>
);
console.log('4. Top.js end')
export default Top;
containers/FilterLink.js
過濾組件
import React from 'react'
import { connect } from "react-redux"
import { setVisibility } from "../actions"
import Link from "../components/Link"
//第二個參數示意組件本身的props
//mapStateToProps()將state節點注入到與view相干的組件
const mapStateToProps = (state, ownProps) => {
// console.log({state,ownProps})
return {
active: ownProps.filter === state.visibilityFilter
}
}
//mapDispatchToProps()將須要綁定的相應事宜注入到組件上
const mapDispatchToProps = (dispatch, ownProps) => {
return {
onClick: () => {
dispatch(setVisibility(ownProps.filter))
}
}
}
//connent()函數天生容器組件
const FilterLink = connect(
mapStateToProps,
mapDispatchToProps
)(Link)
export default FilterLink;
components/Link.js
展現組件,顯現頂部狀況按鈕
import React from 'react';
console.log('3. Link.js start')
const Link = ({ active, children, onClick }) => {
return (
<div className="todo-tab_item">
<a href = "#" style={{ color: active? '#f01414' : '#4d555d' }}
onClick = {
e => {
e.preventDefault()
onClick()
}
}>
{children}
</a>
</div>
)
}
console.log('3. Link.js end')
export default Link;
components/Todo.js
每一個Todo子組件
import React from 'react'
console.log('5. Todo.js start')
//UI 組件有以下幾個特性。
// 只擔任 UI 的顯現,不帶有任何營業邏輯
// 沒有狀況(即不該用this.state這個變量)
// 一切數據都由參數(this.props)供應
// 不該用任何 Redux 的 API
// UI 組件又稱為"純組件",不含狀況,地道由參數決議它的值
const Todo = ({ onClick, completed, text }) => (
<li className='todo-list_li' style={{textDecoration:completed ? "line-through" : "none"}}>
<input type='checkbox' className='pull-left' value='on' onClick={onClick} defaultChecked={completed} />
{text}
</li>
)
console.log('5. Todo.js end')
export default Todo;
containers/VisibleTodoList.js
TodoList列表組件
import React from 'react'
import Todo from '../components/Todo'
import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
console.log('6. VisibleTodoList start')
//擔任治理數據和營業邏輯,不擔任 UI 的顯現
// 帶有內部狀況
// 應用 Redux 的 API
const getVisibleTodos = (todos, filter) => {
console.log('9.2 getVisibleTodos')
switch (filter) {
case 'SHOW_ALL':
return todos;
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed === true)//已完成
case 'SHOW_ACTIVE':
return todos.filter(t => t.completed === false)//未完成
default:
throw new Error('Unknown filter: ' + filter)
}
}
//兼并redux的狀況到react的props中
//將state映照到 UI 組件的參數(props)
//mapStateToProps會定閱 Store,每當state更新的時刻,就會自動實行,從新盤算 UI 組件的參數,從而觸發 UI 組件的從新襯着。
//mapStateToProps的第一個參數老是state對象,還能夠應用第二個參數,代表容器組件的props對象。
//應用ownProps作為參數后,假如容器組件的參數發生變化,也會激發 UI 組件從新襯着。
const mapStateToProps = (state, ownProps) => {
console.log('9.1 mapStateToProps')
// console.log(ownProps)
// console.log(state)
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
}
}
//將用戶對 UI 組件的操縱映照成 Action
//豎立 UI 組件的參數到store.dispatch要領的映照。也就是說,它定義了哪些用戶的操縱應當看成 Action,傳給 Store。它能夠是一個函數,也能夠是一個對象
//假如mapDispatchToProps是一個函數,會獲得dispatch和ownProps(容器組件的props對象)兩個參數。
//mapDispatchToProps作為函數,應當返回一個對象,該對象的每一個鍵值對都是一個映照,定義了 UI 組件的參數如何發出 Action。
//假如mapDispatchToProps是一個對象,它的每一個鍵名也是對應 UI 組件的同名參數,鍵值應當是一個函數,會被看成 Action creator ,返回的 Action 會由 Redux 自動發出。
const mapDispatchToProps = (dispatch) => {
return {
onTodoClick: (id) => {
// console.log(id)
dispatch(toggleTodo(id))
}
}
}
const TodoList = ({ todos, onTodoClick }) => {
console.log('9.3 TodoList')
// console.log(todos);//todos數組
return (
<ul className='list-group'>
{todos.map(todo =>
<Todo
key={todo.id}
{...todo}
onClick={() => onTodoClick(todo.id)}
/>
)}
</ul>
)
}
//React-Redux 供應connect要領,用於從 UI 組件天生容器組件。connect的意義,就是將這兩種組件連起來。
//connect要領接收兩個參數:mapStateToProps和mapDispatchToProps。它們定義了 UI 組件的營業邏輯。前者擔任輸入邏輯,行將state映照到 UI 組件的參數(props),後者擔任輸出邏輯,行將用戶對 UI 組件的操縱映照成 Action。
//connect要領能夠省略mapStateToProps參數,那樣的話,UI 組件就不會定閱Store,就是說 Store 的更新不會引發 UI 組件的更新。
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
console.log('6. VisibleTodoList end')
export default VisibleTodoList;
containers/AddTodo.js
增加Todo子組件
import React from 'react'
import { connect } from 'react-redux'
import { addTodo } from '../actions'
console.log('7. AddTodo.js start')
let AddTodo = ({ dispatch }) => {
let input;
return (
<div>
<form onSubmit={ e => {
console.log('data flow 1')
e.preventDefault();
if (!input.value.trim()) { return }
dispatch(addTodo(input.value))
input.value = ''
} }>
<input placeholder='你想做點什麼' ref={r => input = r
} className='todo-input' autoFocus={true}/>
<button type='submit' className='todo-btn'>
增加使命
</button>
</form>
</div>
)
}
AddTodo = connect()(AddTodo)//把addTodo用redux的connect要領從新包裝一下,使其可應用state中的數據
console.log('7. AddTodo.js end')
export default AddTodo;
翻開終端運轉yarn
或npm install
裝置依靠,運轉npm run build
編譯,運轉npm start
舉行檢察頁面和功用是不是一般
小結:這個階段把頁面和功用完成出來了,開端把全部項目抽離成組件,也應用redux把代碼營業邏輯處置懲罰、狀況治理和狀況分發治理分離出來了
總結:本次todolist的項目因時候關聯中心斷了兩次,也算是“塞翁失馬”吧!我也把這個項目完整地溫習了一遍。這個項目主要把redux的應用以及數據流了解了下,算是也許清晰怎樣玩了,為何說也許呢?一個是因為現在事情中沒有應用,沒法應用到現實項目中,一個就是最外層的index.js,不明白為何console.log是末了打印出來的,也就意味這是末了加載這個文件的,這個文件我的明白不該當是全部項目js的主進口文件嗎?為何反而末了加載呢?不明白,先記下來吧,等今後用到redux了再有認識地研究一下。如今把本身做這個項目的細緻步驟、個人明白以及查閱相干的材料整理出來了,不一定非常正確,假如有哪位大神有差別的看法迎接批評指正!最新了解了react,很喜歡它的組件化開闢,怎樣公司用的倒是JQ,所以在react里我實在還只是個新手,不喜勿噴啊!