日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

create-react-app 脚手架构建项目,搬砖过程中持续总结心得

發(fā)布時(shí)間:2025/7/14 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 create-react-app 脚手架构建项目,搬砖过程中持续总结心得 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

以前都沒用過快速構(gòu)建工具來搭react環(huán)境,這次通過學(xué)習(xí)來走一遍,并且記錄下知識(shí)點(diǎn)(純屬個(gè)人愚見)

1.構(gòu)建出現(xiàn)public文件目錄

  • 架手架 create-react-app demo 后生成public文件-----> public文件 是放一些靜態(tài)資源的,是不會(huì)參與構(gòu)建的,你輸入是怎樣,最終打包構(gòu)建還是怎樣,不像src文件下的代碼會(huì)參與打包構(gòu)建

2.自定義數(shù)據(jù).json 一些操作指令 比如:test文件下有api文件下的data.json

  • test ls ---> 出現(xiàn) api
  • test ls api/ ---> api文件下出現(xiàn)data.json
  • test vi api/data.json -----> 進(jìn)入到 .json 文件
  • 左下角 :q ------> 就是退出該文件

3.create-react-app 已經(jīng)集成了代理轉(zhuǎn)發(fā)的功能,需要在package.json中配置 (要先把mock數(shù)據(jù)放到mock服務(wù)器上并配置5000端口,比如mock服務(wù)器上有很多.json文件)

"proxy":{ "/api":{ (例子)"target": "http://localhost:5000" } } 復(fù)制代碼

4.直接把mock數(shù)據(jù)放在public文件夾下

public文件夾mock文件夾data.json文件{"data":"test"}localhost:3000/mock/data.json 這樣也能拿到mock的模擬數(shù)據(jù) public文件下的內(nèi)容會(huì)原封不動(dòng)的打包到整個(gè)項(xiàng)目當(dāng)中,是一些靜態(tài)資源 復(fù)制代碼

5.父級(jí)傳參到子級(jí),可以通過...擴(kuò)展運(yùn)算符來傳遞

todos是父級(jí)傳給子級(jí)的props todos = [{id:1,text:"1111"},{id:2,text:"2222"}]todos.map(todo=>{return <Todo key={todo.id} {...todo}/> }) 復(fù)制代碼

6.通過...擴(kuò)展運(yùn)算符往舊數(shù)組里加數(shù)據(jù)

const todo = {id: this.indexId++,text: text,completed: true } const newTodoArr = [...this.state.todoArr,todo] 復(fù)制代碼

7.通過...擴(kuò)展運(yùn)算符往舊對(duì)象里里更改某個(gè)數(shù)據(jù)

如果用戶自定義的屬性,放在擴(kuò)展運(yùn)算符后面,則擴(kuò)展運(yùn)算符內(nèi)部的同名屬性會(huì)被覆蓋掉,這用來修改現(xiàn)有對(duì)象部分的部分屬性就很方便了。const newTodo = this.state.todos.map(item=>{return item.id === 1? {...item, completed: !item.completed} :item }) 復(fù)制代碼

8.用redux時(shí),actions文件夾下一般有2個(gè)文件

index.js文件下:import {ADD_TODO, ………等} from "./actionTypes";export addTodo = (text)=>({type:ADD_TODO,text})……………等……………一般情況下 type 同方法名稱相同并且改成大寫即可actionTypes.js文件下:export const ADD_TODO = "ADD_TODO";…… …… …… 復(fù)制代碼

9.用reducer時(shí),reducer文件夾下的index.js文件

const initState = {filter: "",todos: [],text: "" }const todoApp = (state = initState, action)=>{switch(action.type){case ADD_TODO:return {...state,todos:[...state.todos,{id: action.id,text:action.text,completed: false}]}case SET_FILTER:…… ……case SET_TODO_TEXT:…… ……default :return state} } export default todoApp;reducer里的state是不能直接操作的,必須返回一個(gè)新的state,返回新的state對(duì)象的方法有很多,比如 Object.assign({},……)也是其中一種方法 復(fù)制代碼

10. index.js文件下的 reducer拆分

其中一個(gè)例子,分解reducer中的 SET_TODO_TEXT新建一個(gè)text.js 用來拆分 SET_TODO_TEXTimport {…… ……} from ""../actions/actionTypes; const text = (state = "", action)=>{switch (action.type){case SET_TODO_TEXT:return action.textdefault:return state} } export default text分解完上面那個(gè)大reducer之后,把reducer文件夾中的index里面的大reducer刪掉,逐步引入拆分的各個(gè)小的reducerindex.js:import { combineReducers } from "redux";import text from "./text";import …… ……export default combineReducers({text,…… ……});必須安裝redux這個(gè)依賴 npm install redux 因?yàn)閏reate-react-app 并沒有安裝redux 復(fù)制代碼

11. 在src文件夾下創(chuàng)建 store.js

import { createStore } from "redux"; import rootReducer from "./reducers"; import { addTodo ,…… …… } from "./actions";export const store = createStore(rootReducer);// 得到初始的state store.getState() // 訂閱state的變化 store.subscribe(()=>{console.log(store.getState) }) // 發(fā)生actions store.dispatch(addTodo("11111")); 復(fù)制代碼

12. 集成react-redux(容器型組件拆分,編寫 )

  • 向根組件注入 Store -> Provider 組件
  • 連接React組件和redux狀態(tài)層 -> connect
  • 獲取React組件所需的State和Actions -> map api
  • 先安裝react-redux這個(gè)依賴 npm install react-redux 因?yàn)閏reate-react-app 并沒有安裝react-redux
例子:在src下創(chuàng)建containers文件夾,創(chuàng)建TodoListContainer.js文件 容器組件import { connect } from "react -redux";import { toggleTodo } from "../actions";import TodoList from "../components/TodoList";const mapStateToProps = (state)=>({todos: state.todos})const mapDispatchToProps = (dispatch)=>({toggleTodo: id => dispatch(toggleTodo(id))})export default connect(mapStateToProps, //redux中的state映射到react組件當(dāng)中的props上mapDispatchToProps //react組件需要使用的action方法,映射到組件的props當(dāng)中)(TodoList);connect()屬于高階組件,將完成react層和redux層的邏輯連接例子:在src下的components文件夾的App.js文件下 引入containers里的容器組件import { TodoListContainer } from "../containers/TodoListContainer"; import …… ……return (<div><TodoListContainer/>…… ……</div>)例子:在src下的index.js 入口文件import { createStore } from "redux";import { Provider } from "react-redux";import rootReducer from "./reducers";const store = createStore(rootReducer);<Provider store={store}><App/></Provider> 復(fù)制代碼

13. 異步Action 有時(shí)action里會(huì)通過調(diào)用api拿到一些數(shù)據(jù),然后再dispatch(),這樣就存在異步,數(shù)據(jù)會(huì)有延遲

例子:const getTodosSuccess = (data)=>({type: "TODOS_SUCCESS",data})const getTodosFailure = (error)=>({type: "TODOS_FAILURE",error})export const getTodos = ()=> dispatch =>{return new Promise((resolve,reject) => {axios.get({ url: 'xxxxxxxxx'}).then(res=>{dispatch(getTodosSuccess(res))resolve(res)}).catch(err=>{dispatch(getTodosFailure(err))reject(err)})})}getTodos()返回值是一個(gè)函數(shù),這個(gè)函數(shù)我們是無法處理的,所以要借助redux的中間件來完成異步action這個(gè)操作最常用的是 npm install redux-thunk 復(fù)制代碼

14. 異步Action 要用中間件解決 redux-thunk

例子: 在src目錄的 index.js下import thunkMiddleware from "redux-thunk";import { createStore, applyMiddleware } from "redux";const store = createStore(rootReducer, applyMiddleware(thunkMiddleware))這樣創(chuàng)建出來的store 就能處理異步action了 復(fù)制代碼

15. 谷歌瀏覽器安裝redux調(diào)試工具

在github上尋找 redux-devtools-extension找到 Advanced store setupif you setup your store with middleware and enhancers,change:xxxxxxxxxxxxxxxxxxxxxxxxxxx 這里的東西可以用,復(fù)制下來在src目錄的 index.js下import { compose } from "redux"; //compose這個(gè)函數(shù)可以幫助我們將多個(gè)enhancers組合到一起,compose是個(gè)增強(qiáng)器可以增加store的功能const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION__COMPOSE__ || compose;const store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunkMiddleware))); 復(fù)制代碼

16. 項(xiàng)目結(jié)構(gòu)組件方式

按照類型:action/-- action1.js action2.jscomponents/-- component1.js component2.jsreducers/-- reducer1.js reducer2.js index.js(所有reducer組合成一個(gè))containers/ (容器型組件)-- containser1.js containser2.js按照功能模塊:(存在不同模塊之間狀態(tài)互相耦合的場(chǎng)景)feature1/-- components/-- Container.js-- actions.js-- reducer.jsfeature2/-- components/-- Container.js-- actions.js-- reducer.jsDucks: ………… 復(fù)制代碼

17. Middleware(中間件) 增強(qiáng)store dispatch的能力

例子:redux-thunk 可以處理函數(shù)類型的action了View -> ( mid1 -> mid2 -> …… …… ) -> reducer //頁面觸發(fā)action 會(huì)逐步經(jīng)過這些中間件,增強(qiáng)dispatch,dispatch所做的事就是派發(fā)actionFunction:({getState, dispatch}) => next => action在src文件夾下 新建 Middleware文件夾->logger.js// 打印action, state 的logger中間件const logger = ({getState, dispatch}) => next => action => {console.group(action.type);console.log("dispatching:", action);const result = next(action);console.log("next state:", getState()); consoel.groupEnd();return result;}export default logger;在index.js文件下 ,把自己寫的中間件加進(jìn)去import loggerMiddleware from "./middleware/logger";const store = createStore(…… ……applyMiddleware(…… ……,loggerMiddleware)) 復(fù)制代碼

18. store enhancer 增強(qiáng)redux store的功能

store enhancer 一般結(jié)構(gòu):function enhancerCreator(){return createStore => (...arg) => {// do something based old store// return a new enhanced store}}在src文件夾下 新建enhancer文件夾 -> logger.js// 打印action, state 的增強(qiáng)器const logger = createStore => (...arg) => {const store = createStore(...arg);const dispatch = (action) => {console.group(action.type);console.log("dispatching:", action);const result = store.dispatch(action);console.log("next state:", store.getState()); consoel.groupEnd();return result;}return {...store, dispatch} // 把新的dispatch方法覆蓋到原來對(duì)象的dispatch}export default logger;在index.js文件下 ,把自己寫的enhancer加進(jìn)去import loggerEnhancer from "./enhancer/logger";const store = createStore(…… ……compose(applyMiddleware(thunkMiddleware), loggerEnhancer))compose是可以把多個(gè) store enhancer 進(jìn)行組合的在平時(shí)中應(yīng)該盡量多使用 Middleware 來增強(qiáng)dispatch的能力, 慎用 store enhancer 記住! 復(fù)制代碼

18. Immutable.js 可以用來創(chuàng)建不可變的對(duì)象state 每次都可以返回個(gè)新的

npm install immutable npm install redux-immutableimport Immutable from "immutable"; import { combineReducers } from "redux-immutable"; const initState = {…… ……,isFetching: false,todos: {……,data: []} }//這樣就創(chuàng)建了一個(gè)不可變的 immutable 對(duì)象 const state = Immutable.fromJS(initState) //設(shè)置屬性,一次只能設(shè)置一個(gè)key state.set("isFetching", true); //merge可以一下設(shè)置多個(gè) state.merge({isFetching: false,todos: Immutable.fromJS(action.data) // 數(shù)據(jù)類型一定要統(tǒng)一用immutable的類型 });//get得到屬性的值 state.get("isFetching");//getIn 從外層到內(nèi)層逐層獲取 state.getIn(["todos","data"]);//把immutable對(duì)象轉(zhuǎn)化成普通JS對(duì)象 state.toJS(); 因?yàn)樵?mapStateToProps,…… 的對(duì)象要普通JS對(duì)象才能使用在reducers文件下的 index.js中import { combineReducers } from "redux-immutable"; // redux中的combineReducers只能識(shí)別普通JS對(duì)象 復(fù)制代碼

19. Reselect庫經(jīng)常和redux一起使用, Reselect減少state的重復(fù)計(jì)算

npm install reselectimport { createSelector } from "reselect"const getFilter = (state) => state.filter; const getTodos = (state) => state.todos.data;export const getVisibleTodos = createSelector([getTodos,getFilter], //數(shù)組里面是其他所依賴的select函數(shù)(todos, filter) => { //前2個(gè)函數(shù)返回的數(shù)據(jù)結(jié)果,可用來計(jì)算console.log("-----"); //用來測(cè)試看有沒多余的重復(fù)執(zhí)行switch(filter){case: "xxx":returncase ……:……default:……}} );只有當(dāng)select函數(shù)確實(shí)非常復(fù)雜并且整個(gè)redux性能有很大的問題才去考慮用reselect,并不是必須的 復(fù)制代碼

20. Router相關(guān)庫

  • react-router
  • react-router-dom
  • react-router-native
  • 建議在項(xiàng)目之中使用<BrowserRouter>組件
react-router這個(gè)庫實(shí)現(xiàn)了路由的核心功能,react-router-dom是在react-router之上的一層封裝,將react-router的路由功能和web的API進(jìn)行了綁定<Router>常用組件: <BrowserRouter>1 . Html5 history API (pushState, repalceState等)2. 需要Web服務(wù)器額外配置localhost:3000/home localhost:3000/about<Router>常用組件: <HashRouter>1. 使用url的hash部分作為路由的信息2. 主要為了兼容老版本瀏覽器localhost:3000/#/home localhost:3000/#/about 復(fù)制代碼

21. 路由配置:Route

<BrowserRouter><Route path="/" exact component={Home}/><Route path="/about" component={About}/><Route path="/user/:aaa" component={User}/>…… …… <BrowserRouter/>組件中得到傳過來的參數(shù): this.props.match.params.aaa 復(fù)制代碼

22. 路由匹配

<Route exact /> exact : url和path完全相同的情況下才會(huì)匹配成功import { Switch } from "react-router-dom"; <Switch><Route path="/about" component={About}/><Route path="/user/:aaa" component={User}/><Route path="/" component={Home}/> // 當(dāng)前面都匹配不成功時(shí),根路徑才會(huì)被匹配 <Switch/>Swicth 的功能是會(huì)去匹配第一個(gè),被匹配到的<Route />,當(dāng)?shù)谝粋€(gè)<Route/>匹配到的時(shí)候,其他的<Rpute>都不會(huì)被匹配 復(fù)制代碼

23. 路由渲染組件的方式

  • <Route component />
  • <Rute render />
  • <Route children />
<Route path="/about" render={(props) => <About {...props}/> //props是一個(gè)對(duì)象,包含了match,location,history } />在App.js:<Router><Route path="/user" component={User}></Router> 在User.js:<div><Route path={`${this.props.match.path}/:user`} component={UserDetail}></div> 在UserDetail.js:<div>this.props.match.params.user</div> 復(fù)制代碼

24. create-rwact-app 創(chuàng)建出來的默認(rèn)的入口文件

// If you want your app to work offline and load faster, you can change// unregister() to register() below. Note this comes with some pitfalls.// Learn more about service workers: https://bit.ly/CRA-PWAserviceWorker.unregister();serviceWorker 離線存儲(chǔ),加載優(yōu)化的事情, 做項(xiàng)目時(shí)沒使用到的話要把這句話刪掉 復(fù)制代碼

25. store.js 文件中的 process.env.NODE_ENV 環(huán)境變量 && 判斷瀏覽器有沒裝redux調(diào)試工具

判斷當(dāng)年程序的執(zhí)行是開發(fā)環(huán)境還是生產(chǎn)環(huán)境 && 如果瀏覽器安裝redux的調(diào)試工具 window對(duì)象下會(huì)有redux的調(diào)試方法添加進(jìn)去if (process.env.NODE_ENV !== "production" &&window.__REDUX_DEVTOOLS_EXTENSION__){const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__; // 作為store的增強(qiáng)器store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunk))); // 將REDUX_DEVTOOLS的功能增強(qiáng)到store當(dāng)中} else {store = createStore(rootReducer, applyMiddleware(thunk));}復(fù)制代碼

26. fetch()或者 axios 請(qǐng)求url

axios 優(yōu)缺點(diǎn):- 從 node.js 創(chuàng)建 http 請(qǐng)求。- 支持 Promise API。- 提供了一些并發(fā)請(qǐng)求的接口(重要,方便了很多的操作)。- 在瀏覽器中創(chuàng)建 XMLHttpRequests。- 在 node.js 則創(chuàng)建 http 請(qǐng)求。(自動(dòng)性強(qiáng))- 支持 Promise API。- 支持?jǐn)r截請(qǐng)求和響應(yīng)。- 轉(zhuǎn)換請(qǐng)求和響應(yīng)數(shù)據(jù)。- 取消請(qǐng)求。- 自動(dòng)轉(zhuǎn)換 JSON 數(shù)據(jù)。- 客戶端支持防止CSRF。- 客戶端支持防御 XSRF。Fetch 鏈接 https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch (MDN)axios既提供了并發(fā)的封裝,也沒有fetch的各種問題,而且體積也較小,當(dāng)之無愧現(xiàn)在最應(yīng)該選用的請(qǐng)求的方式。 復(fù)制代碼

27. 中間件的業(yè)務(wù)流程

文件 ./entities/products.jsexport const schema = {name: "products",id: "id"}…… …… ……*****************************************************文件 ./redux/home.jsimport FETCH_DATA from "../middleware/api"import schema from "./entities/products"export const types = {FETCH_LIKES_REQUEST:"FETCH_LIKES_REQUEST",FETCH_LIKES_SUCCESS:"FETCH_LIKES_SUCCESS",FETCH_LIKES_FAILURE:"FETCH_LIKES_FAILURE"}export const actions = {loadLikes: ()=>{return (dispatch, getState) => {const endpoint = url.getProductList(0,10); // utils中的方法返回一個(gè)url路徑return dispatch(fetchLikes(endpoint));}}}const fetchLikes = (endpoint)=>({[FETCH_DATA]: { types:[types.FETCH_LIKES_REQUEST,types.FETCH_LIKES_SUCCESS,types.FETCH_LIKES_FAILURE],endpoint,schema},});…… …… ……*****************************************************文件 middleware/api.jsexport const FETCH_DATA = "FETCH_DATA";export default store => next => action => {const callAPI = action[FETCH_DATA];if(typeof callAPI === "undefined"){return next(action);}const { endpoint, schema, types } = callAPIif(typeof endpoint !== "string"){throw new Error("endpoint要為字符串類型的url");}if(!schema){throw new Error("必須指定領(lǐng)域?qū)嶓w的schema");}if(!Array.isArray(types) && types.length !== 3){throw new Error("需要指定一個(gè)包含了3個(gè)action type的數(shù)組");}if(!types.every(type => typeof type === "string")){throw new Error("action types 必須為字符串類型");}// 里面有新東西,增強(qiáng)dispatch()const actionWith = (data) =>{const finalAction = {...action, ...data};delete finalAction[FETCH_DATA];return finalAction }const [requestType, successType, failureType] = types;next(actionWith({type: requestType}));return fetchData(endpoint, schema).then(response => next(actionWith({type: successType,response})),error => next(actionWith({type: failureType,error: error.message || "獲取數(shù)據(jù)失敗"})) )};// 執(zhí)行網(wǎng)絡(luò)請(qǐng)求const fetchData = (endpoint, schema) => {return get(endpoint).then(data => {return normalizeDate(data,schema)})}// 根據(jù)schema,將獲取的數(shù)據(jù)扁平化處理const normalizeDate = (data,schema) => {const { id,name } = schema;let kvObj = {};let ids = [];if(Array.isArray(data)){data.forEach(item => {kvObj[item[id]] = item;ids.push(item[id]);})}else{kvObj[data[id]] = data;ids.push(data[id]);}return { [name]: kvObj,ids}} 復(fù)制代碼

結(jié)語

前端react QQ群:788023830 ---- React/Redux - 地下老英雄

前端交流 QQ群:249620372 ---- FRONT-END-JS前端

(我們的宗旨是,為了加班,為了禿頂……,仰望大佬),希望小伙伴們加群一起學(xué)習(xí)

轉(zhuǎn)載于:https://juejin.im/post/5cc96be351882540b244d601

總結(jié)

以上是生活随笔為你收集整理的create-react-app 脚手架构建项目,搬砖过程中持续总结心得的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。