摘要:為了提高自己的學習效率,避免做一些無用的工作,我也決定以后無論是工作還是學習一定要養成定時總結的習慣,而且也要用文字記錄下來,這樣可以時常復習,理清邏輯,加深印象。一種解決方法是將對象作為參數,傳入容器組件。
前言
最近一直在學習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
index.jsRedux Todos Example
import第三方依賴包和css文件
import React from "react" import { render } from "react-dom" import "./components/app.css" render( , 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(reducers/index.js,document.getElementById("root") ) console.log("9. root index end")
把數據邏輯處理的代碼抽離成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 = () => (components/Top.js) console.log("8. App.js end") export default App;
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 = () => (containers/FilterLink.js); console.log("4. Top.js end") export default Top;全部任務 待辦任務 已完成任務
過濾組件
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 ( ) } 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 }) => (
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 (
添加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 (打開終端運行yarn或npm install安裝依賴,運行npm run build編譯,運行npm start進行查看頁面和功能是否正常) } AddTodo = connect()(AddTodo)//把addTodo用redux的connect方法重新包裝一下,使其可使用state中的數據 console.log("7. AddTodo.js end") export default AddTodo;{ console.log("data flow 1") e.preventDefault(); if (!input.value.trim()) { return } dispatch(addTodo(input.value)) input.value = "" } }> input = r } className="todo-input" autoFocus={true}/>
小結:這個階段把頁面和功能實現出來了,初步把整個項目抽離成組件,也利用redux把代碼業務邏輯處理、狀態管理和狀態分發管理分離出來了
總結:本次todolist的項目因時間關系中間斷了兩次,也算是“因禍得福”吧!我也把這個項目完整地復習了一遍。這個項目主要把redux的運用以及數據流了解了下,算是大概清楚怎么玩了,為什么說大概呢?一個是因為目前工作中沒有使用,無法運用到實際項目中,一個就是最外層的index.js,不明白為什么console.log是最后打印出來的,也就意味這是最后加載這個文件的,這個文件我的理解不應該是整個項目js的主入口文件嗎?為什么反而最后加載呢?不明白,先記下來吧,等以后用到redux了再有意識地研究一下。現在把自己做這個項目的詳細步驟、個人理解以及查閱相關的資料整理出來了,不一定十分準確,如果有哪位大神有不同的意見歡迎批評指正!最新了解了react,很喜歡它的組件化開發,奈何公司用的卻是JQ,所以在react里我其實還只是個新手,不喜勿噴啊!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94814.html
摘要:二基礎就是一個普通的。其他屬性用來傳遞此次操作所需傳遞的數據,對此不作限制,但是在設計時可以參照標準。對于異步操作則將其放到了這個步驟為添加一個變化監聽器,每當的時候就會執行,你可以在回調函數中使用來得到當前的。 注:這篇是16年10月的文章,搬運自本人 blog...https://github.com/BuptStEve/... 零、環境搭建 參考資料 英文原版文檔 中文文檔 墻...
摘要:框架的使用詳解及教程在前段時間,我們也學習講解過框架的基本使用,但是有很多同學在交流群里給我的反饋信息說,框架理解上有難度,看了之后還是一臉懵逼不知道如何下手,很多同學就轉向選擇使用框架。 dva框架的使用詳解及Demo教程 在前段時間,我們也學習講解過Redux框架的基本使用,但是有很多同學在交流群里給我的反饋信息說,redux框架理解上有難度,看了之后還是一臉懵逼不知道如何下手,很...
摘要:而函數式編程就不一樣了,這是模仿我們人類的思維方式發明出來的。數據流在中,數據的流動是單向的,即從父節點傳遞到子節點。數據流嚴格的單向數據流是架構的設計核心。 前言 總括: 本文采用react+redux+react-router+less+es6+webpack,以實現一個簡易備忘錄(todolist)為例盡可能全面的講述使用react全家桶實現一個完整應用的過程。 代碼地址:Re...
摘要:首先聲明這篇文章是想說明一下最新版本的的新特性帶來的極大的開發體驗提升而不是如何利用開發應用這個特性就是對的支持在的中有說明具體可以參考這里在版本之前我們在開發應用尤其是在配合一類庫的時候經常用到諸如之類的封裝而這些函數其實都可以用裝飾器的 首先聲明, 這篇文章是想說明一下最新版本的 TypeScript(3.0) 的新特性帶來的極大的 React 開發體驗提升. 而不是如何利用 Ty...
摘要:是流行的框架之一,在年及以后將會更加流行。于年首次發布,多年來廣受歡迎。下面是另一個名為的高階函數示例,該函數接受另外兩個函數,分別是和。將所有較小的函數組合成更大的函數,最終,得到一個應用程序,這稱為組合。 React是流行的javascript框架之一,在2019年及以后將會更加流行。React于2013年首次發布,多年來廣受歡迎。它是一個聲明性的、基于組件的、用于構建用戶界面的高...
閱讀 1768·2023-04-26 01:44
閱讀 1211·2021-11-12 10:34
閱讀 1579·2021-09-09 09:33
閱讀 1729·2019-08-30 15:44
閱讀 2893·2019-08-30 13:49
閱讀 2191·2019-08-29 15:26
閱讀 944·2019-08-26 13:30
閱讀 1409·2019-08-23 18:15