初探react,用react实现一个todoList功能
初探react,用react實現一個todoList功能
- 🛰?前言
- 🚀一、react基礎
- 1. react簡介
- 2. 開發環境搭建
- 3. 工程目錄文件簡介
- 4. react中最基礎的JSX語法
- 🛸二、使用react編寫TodoList功能
- 1. 頁面構思
- 2. React中的響應式設計思想和事件綁定
- 3. 實現TodoList新增刪除功能
- (1)新增功能
- (2)刪除功能
- 🪐三、對TodoList功能進行進階操作
- 1. JSX語法細節補充
- (1)自動轉義
- (2)光標聚焦
- 2. 拆分組件與組件之間的傳值
- 3. TodoList代碼優化
- 🌠四、圍繞React衍生出的思考
- 🌌五、結束語
- ??彩蛋
🛰?前言
對于前端而言, react 是前端三大主流框架之一。而在現實生產中,基本上很多大型公司也會偏向于使用 react ,原因在于 react 的 diy 能力比起其他框架也會稍微要更好一些~
緊跟著新技術的步伐,周一也開始學期了 react 。那在下面的文章中,將講解關于 react 的一些基礎知識點,同時呢,也將用 react 來實現一個 TodoList 的功能。
叮咚,開始奇妙的 eract 之旅~🚋
🚀一、react基礎
在對 todoList 功能進行設計之前,我們先來了解一點 react 相關的基礎知識。
1. react簡介
對于 reactjs 來說,需要了解的一些基礎知識主要有以下幾點:
- reactjs → react native → react VR ;
- 由 Facebook 推出的一款框架,于 2013 年開源于社區;
- react 擁有豐富的函數式編程;
- react 目前在全球范圍內,是使用人數最多的前端框架,同時它擁有健全的文檔與完善的社區;
- React Fiber 是 React 16 的版本,它為 React 做了很多底層的優化。
2. 開發環境搭建
在進入 react 的基礎學習之前,我們首先來搭建 react 的開發環境。對于 react 的環境搭建來說,一般有兩種方式,分別是:
- 通過引入 .js 文件來使用 React ;
- 通過腳手架工具來編碼,比如 GRUNT 、 Gulp 和 webpack ;
- 使用 create-react-app 來搭建環境。
那么現在,我們用 create-react-app 來搭建一個 react 項目。具體命令行如下:
npx create-react-app my-app cd my-app npm start3. 工程目錄文件簡介
初始化完一個項目后,我們來了解下 react 的項目結構。具體如下:
├── public├── favicon.ico 網頁icon├── index.html 首頁的html模板├── manifest.json 緩存文件 ├── src├── App.css ├── App.js 填寫組件的內容├── App.test.js 自動化測試文件├── index.css├── index.js 整個程序運行的入口文件├── logo.svg├── registerServiceWorker 借助網頁寫手機app的功能 ├── README.md 項目的說明文件 ├── yarn.lock 項目依賴安裝包的一些版本號4. react中最基礎的JSX語法
以前我們在寫像 <div></div> 這種類似的語法時,一般都是寫在 HTML 文件里面。那么,在 react 中,像 <div></div> 這種類型的代碼,是在 JS 中去寫的。因此,在 js 中寫的 html 代碼,被稱之為 jsx 語法。
值得注意的是,在 react 中使用自己定義的組件時,組件名必須以大寫為開頭,小寫開頭在 jsx 中是不支持的,這一點需要稍微注意一下。
所以,一般看到以大寫為開頭時,比如 <App /> ,則說明是我們自己定義的組件。如果是小寫為開頭時,則一般是原始的 HTML5 標簽,如 <div></div> 。
🛸二、使用react編寫TodoList功能
1. 頁面構思
首先,我們需要先來對頁面的內容進行構造。我們在項目的 src文件夾下創建一個文件,命名為 TodoList 。具體代碼如下:
import React, { Component, Fragment } from 'react';class TodoList extends Component {render() {return (<Fragment><div><input /><button></button></div><ul><li>學英語</li><li>Learning React</li></ul></Fragment>)} }export default TodoList;此時瀏覽器的顯示效果如下:
2. React中的響應式設計思想和事件綁定
上面我們簡單了顯示了 todolist 的基本功能,那現在,我們想要實現的是,點擊提交按鈕,可以把 input 框里面的內容顯示在列表下方,這又該怎么處理呢?
如果按照我們正常的思維來想的話,我們可能會覺得,在提交按鈕中綁定一個事件,之后呢,當點擊綁定按鈕時,獲取到 input 框的值,進行綁定提交。
但事實上, react 強調的是,我們不要直接操作 DOM ,而是要操作數據。當數據發生變化時, react 會自動地感知到我們數據發生的變化,會自動地幫我們生成 DOM 。
因此,在寫 react 時,我們不需要關心 DOM 層面的操作,只需要去關心數據層面的操作即可。
現在,我們先來監聽 input 框的值。具體代碼如下:
import React, { Component, Fragment } from 'react';class TodoList extends Component {constructor(props) {super(props);this.state = {inputValue: 'hello!!',list: []}}render() {return (<Fragment><div><input value = {this.state.inputValue}onChange = {this.handleInputChange.bind(this)}/><button>提交</button></div><ul><li>學英語</li><li>Learning React</li></ul></Fragment>)}handleInputChange(e) {this.setState({inputValue: e.target.value})} }export default TodoList;此時瀏覽器的打印效果為:
大家可以看到,我們正確的使得 input 框響應到了數據。
那在上面的這段代碼中,需要了解的知識點有以下幾點。分別是:
- state 負責存儲組件中的數據;
- 如果想要在 html 代碼中用一些 js 的表達式,那么要記得用 {} 進行包裹;
- 在進行事件綁定時,記得使用 bind(this) 對事件的作用域進行變更;
- 當你想要改變數據項時,不能直接使用 this.state 來改變數據的值,要通過 setState 函數來進行改變。
3. 實現TodoList新增刪除功能
(1)新增功能
在上面的例子中,我們實現了 input 框中值的獲取。那現在,我們要來實現點擊提交這個按鈕,能夠實現對 input 框中值的新增。同樣地,是在 TodoList.js 文件下進行修改。具體代碼如下:
import React, { Component, Fragment } from 'react';class TodoList extends Component {constructor(props) {super(props);this.state = {inputValue: 'Monday',list: []}}render() {return (<Fragment><div><input value = {this.state.inputValue}onChange = {this.handleInputChange.bind(this)}/><button onClick={this.handleBtnClick.bind(this)}>提交</button></div><ul>{this.state.list.map((item, index) => {return <li key={index}>{ item }</li>})}</ul></Fragment>)}handleInputChange(e) {this.setState({inputValue: e.target.value})// console.log(e.target.value)}handleBtnClick() {// ... 展開運算符會將之前的數組進行展開,并生成一個全新的數組// 將input框的值和list的值進行合并形成一個新的數組this.setState({list: [...this.state.list, this.state.inputValue],inputValue: ''})} }export default TodoList;此時瀏覽器的顯示效果如下:
在上面的代碼中,需要了解的知識點有:
- 我們先在 button 中綁定了 handleBtnClick 事件;
- 之后通過展開運算符 ... ,將數組的內容給合并到 list 數組中;
- 最后,使用 js 中的 map() 方法,將數組列表中的內容給遍歷出來。
(2)刪除功能
繼續,我們來實現刪除功能。具體代碼如下:
import React, { Component, Fragment } from 'react';class TodoList extends Component {constructor(props) {super(props);this.state = {inputValue: 'Monday',list: []}}render() {return (<Fragment><div><inputvalue={this.state.inputValue}onChange={this.handleInputChange.bind(this)}/><button onClick={this.handleBtnClick.bind(this)}>提交</button></div><ul>{this.state.list.map((item, index) => {return (<likey={index}onClick={this.handleItemDelete.bind(this, index)}>{item}</li>)})}</ul></Fragment>)}handleInputChange(e) {this.setState({inputValue: e.target.value})}handleBtnClick() {this.setState({list: [...this.state.list, this.state.inputValue],inputValue: ''})}handleItemDelete(index) {const list = [...this.state.list];list.splice(index, 1);this.setState({list: list})} }export default TodoList;在上面的代碼中,我們在每一個 <li> 標簽下綁定了 handleItemDelete 事件,之后呢,通過傳遞它的 id 值 index ,同時,配合 splice() 方法,來刪除掉掉 list 中具體的內容。
值得注意的是,在 react 中,它是不允許我們對 state 做任何改變的。比如說,我們想要把上面刪除代碼的邏輯這么寫:
handleItemDelete(index) {this.state.list.splice(index, 1);this.setState({list: this.state.list}) }如果我們直接去操作 this 來改變最后的結果,這會使得函數變得很難用。同時,這種方式在 react 中也是不允許滴!這是應該注意的一個點!
🪐三、對TodoList功能進行進階操作
1. JSX語法細節補充
(1)自動轉義
如果在 jsx 中,我們希望顯示一些內容,且這些內容我們希望它自動轉義。像下圖這樣:
大家可以看到,如果不轉義時,那么它直接顯示除出了 <h1></h1> 標簽。但其實我們希望的是,想要把它轉義成一級標簽的內容。那應該怎么處理呢?
我們就通過 dangerouslySetInnerHTML 這個屬性來對 html 進行設置,已達到對 <li> 標簽下的內容進行改變,具體代碼如下:
<likey={index}onClick={this.handleItemDelete.bind(this, index)}dangerouslySetInnerHTML={{ __html: item }}> </li>我們來看下顯示效果:
通過對 dangerouslySetInnerHTML 的設置,我們 html 的內容進行了轉義。
(2)光標聚焦
在實際的實踐中,對于 input 框來說,我們往往會想要點擊某個文本,然后讓它去聚焦到 input 框中輸入內容。那這應該怎么處理呢?
我們繼續來改造 jsx 代碼。具體代碼如下:
render() {return (<Fragment><div><label htmlFor="insertArea">輸入內容</label><inputid="insertArea"className="input"value={this.state.inputValue}onChange={this.handleInputChange.bind(this)}/><button onClick={this.handleBtnClick.bind(this)}>提交</button></div><ul>{this.state.list.map((item, index) => {return (<likey={index}onClick={this.handleItemDelete.bind(this, index)}dangerouslySetInnerHTML={{ __html: item }}></li>)})}</ul></Fragment>)}此時瀏覽器的顯示效果為:
大家可以看到,當我們點擊輸入內容這四個字時,光標就自動地聚焦到 input 框上,并且能夠進行自由地輸入。那這樣的功能是怎么實現的呢?
在上面的代碼中,我們可以看到,通過 label 標簽和 htmlFor 來對內容進行綁定,以達到最終我們想要實現的效果。
2. 拆分組件與組件之間的傳值
在實際的項目中,對于一個大的組件來說,我們總是會對其進行組件拆分。那對于上面這個 todoList 組件來說,也不例外。
我們可以把①輸入內容,② input 框 和 ③提交按鈕拆分成一個組件。之后呢,把 list 列表拆分成另外一個組件。那接下來我們來對這個組件進行拆分以及父子組件間數據的傳遞。
首先我們在項目的 src 文件夾下添加一個新的文件。命名為 TodoItem.js 。具體代碼如下:
import React, { Component } from 'react';class TodoItem extends Component {constructor(props) {super(props);this.handleClick = this.handleClick.bind(this);}render() {return (<divonClick={this.handleClick}>{this.props.content}</div>)}handleClick() {this.props.deleteItem(this.props.index);} }export default TodoItem;現在,我們來改造 TodoList.js 文件。具體代碼如下:
import React, { Component, Fragment } from 'react'; import './style.css'; import TodoItem from './TodoItem';class TodoList extends Component {constructor(props) {super(props);this.state = {inputValue: 'Monday',list: []}}render() {return (<Fragment><div><label htmlFor="insertArea">輸入內容</label><inputid="insertArea"className="input"value={this.state.inputValue}onChange={this.handleInputChange.bind(this)}/><button onClick={this.handleBtnClick.bind(this)}>提交</button></div><ul>{this.state.list.map((item, index) => {return (<div>{/* 父組件將content,index 和 deleteItem 將對應的內容傳遞給子組件 */}<TodoItemcontent={item}index={index}deleteItem={this.handleItemDelete.bind(this)}/>{/*<likey={index}onClick={this.handleItemDelete.bind(this, index)}dangerouslySetInnerHTML={{ __html: item }}></li>*/}</div>)})}</ul></Fragment>)}handleInputChange(e) {this.setState({inputValue: e.target.value})// console.log(e.target.value)}handleBtnClick() {// ... 展開運算符會將之前的數組進行展開,并生成一個全新的數組// 將input框的值和list的值進行合并形成一個新的數組this.setState({list: [...this.state.list, this.state.inputValue],inputValue: ''})}handleItemDelete(index) {const list = [...this.state.list];list.splice(index, 1);this.setState({list: list})} }export default TodoList;就這樣,我們對組件進行拆分,達到了與上面未拆分前一樣的效果。
那現在,我們來梳理下其中的知識點。主要有以下兩個知識點:
- 如何進行組件的拆分
- 父組件向子組件傳遞值,應該怎么傳遞
首先,我們創建了一個新的文件 TodoItem ,來存放列表的內容,這是第一點。
其次,有了列表的內容后,我們要來想,父子組件間的數據,怎么傳遞。那事實上,父組件向子組件傳遞內容,通過屬性的形式來傳遞。大家看到父組件中 <TodoItem /> 的位置,在父組件中,通過 content={item} 這樣的形式,來把 item 命名為 content ,并將其傳遞給子組件。
而對于子組件 <TodoItem /> 來說,它將以 this.props 的方式來調用父組件的數據和事件。
3. TodoList代碼優化
在上面的代碼中,我們對組件進行拆分,以及實現了父子組件間的數據傳遞。
但細心的小伙伴可能已經發現,代碼這么寫可能還不夠美觀。因此,我們來對這兩個組件的代碼進行優化。
首先是 TodoItem.js 。具體代碼如下:
import React, { Component } from 'react';class TodoItem extends Component {constructor(props) {super(props);this.handleClick = this.handleClick.bind(this);}render() {const { content } = this.props;return (<div onClick={this.handleClick}>{/* {this.props.content} */}{content}</div>)}handleClick() {const { deleteItem, index } = this.props;deleteItem(index);} }export default TodoItem;我們把 this.props 給單獨提取出來,之后再將其放在組件當中使用。同時呢,我們還對 this.handleClick.bind(this) 單獨提取出來,這樣也使得組件更加美觀。
其次,我們來改造 TodoList.js 。具體代碼如下:
import React, { Component, Fragment } from 'react'; import TodoItem from './TodoItem'; import './style.css';class TodoList extends Component {constructor(props) {super(props);this.state = {inputValue: 'Monday',list: []}this.handleInputChange = this.handleInputChange.bind(this);this.handleBtnClick = this.handleBtnClick.bind(this);this.handleItemDelete = this.handleItemDelete.bind(this);}render() {return (<Fragment><div><label htmlFor="insertArea">輸入內容</label><inputid="insertArea"className="input"value={this.state.inputValue}onChange={this.handleInputChange}/><buttononClick={this.handleBtnClick}>提交</button></div><ul>{this.getTodoItem()}</ul></Fragment>)}getTodoItem() {// 父組件將content,index 和 deleteItem 將對應的內容傳遞給子組件return this.state.list.map((item, index) => {return (< TodoItemkey={index}content={item}index={index}deleteItem={this.handleItemDelete}/>)})}handleInputChange(e) {const value = e.target.value;this.setState(() => ({inputValue: value}));// console.log(e.target.value)}handleBtnClick() {// prevState表示在修改數據之前數據是怎么樣的,避免不小心的改變state的狀態this.setState((prevState) => ({list: [...prevState.list, prevState.inputValue],inputValue: ''}));}handleItemDelete(index) {this.setState((prevState) => {const list = [...prevState.list];list.splice(index, 1);return { list };});} }export default TodoList;同樣地,我們先把 handleInputChange 、 handleBtnClick 、 handleItemDelete 這三個事件給抽離出來。
其次呢,我們把 this.state.list.map() 給單獨出來形成 getTodoItem() 方法,并使用 {this.getTodoItem()} 進行調用。
最后,我們分別對事件中的 this.setState({}) 進行升級改造,將當前所有事件中的所有數據都封裝在一個函數內。
🌠四、圍繞React衍生出的思考
上面我們基本完成了對 TodoList 功能的開發。那么現在,我們將圍繞著我們所學的,來衍生出 react 的一些番外的知識點。具體如下:
- 聲明式開發 —— 以前我們在 js 的開發中,都是大量的操作 DOM ,這種開發方式稱為命令式開發。到現在,我們在使用 react 時,基本都是直接操作數據,而不是操作 DOM 。那么這樣的開發方式,被稱為是聲明式開發。
- 可以與其他框架并存
- 組件化方式開發
- 單向數據流 —— 在 react 中,父組件允許往子組件傳值,但是子組件只能去使用這個值,而不能去改變這個值。
- 視圖層框架 —— 只幫助我們解決數據和頁面上的內容,并不負責組件間怎么傳值,如何傳值。
- 函數式編程 —— 當一個函數內容變得多時,可以進行拆分。每一個函數各司其職,使得代碼更具有維護性。同時,給前端的自動化測試帶來巨大的便捷性。
🌌五、結束語
在上面的文章中,我們學到了關于 react 的一些基礎知識。除此之外呢,我們還對 TodoList 進行了基礎編寫和進階操作編寫。與此同時,我們還圍繞 React 衍生出了一些思考。不知道小伙伴們是否對 react 有一些了解了呢?
??彩蛋
- 關注公眾號星期一研究室,第一時間關注優質文章,更有面試專欄待你解鎖~
- 如果您覺得這篇文章有幫助到您的的話不妨點贊支持一下喲~~😉
- 以上就是本文的全部內容!我們下期見!👋👋👋
總結
以上是生活随笔為你收集整理的初探react,用react实现一个todoList功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 创新视角下的复盘 | 2021/08/0
- 下一篇: 女生轻薄本怎么选如何选择女生电脑