[React] Review
React.js 中文开发入门教学 + Next.js 为这次的重点~
建立简单的工程
关于 Html 部分
-
Create
# Init. (react-learning) jeffrey@JeffreyH:~/.../web$ node -v v14.18.2 # Node 自带npm 模块,所以可以直接使用npx 命令。 (react-learning) jeffrey@JeffreyH:~/.../reactweb$ npx -v 6.14.15 npx create-react-app reactweb # 脚手架工具
cd reactweb/ npm start
-
Structure
reactweb/ ├── node_modules ├── package.json ├── package-lock.json ├── public │ ├── favicon.ico │ ├── index.html # (1) id="root", ref: 24:28 启动文件 │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json # Jeff: 生成 pwa应用 时用到的文件, 渐进式Web应用 │ └── robots.txt # Jeff: 搜索引擎优化用到的文件 ├── README.md ├── run.sh └── src ├── App.css ├── App.js ├── App.test.js ├── index.css ├── index.js # 整个工程的应用入口 ├── logo.svg ├── reportWebVitals.js └── setupTests.js
-
index.js 文件
html.js 中的root 的内容的具体定义来自于这里。而 App.js则定义了默认的页面。
import React from 'react'; import ReactDOM from 'react-dom/client'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <App /> </React.StrictMode> ); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals();
npm可以替换掉react-scripts默认的命令。
"scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" },
关于 CSS 部分
-
Tailwind CSS
现做如下四步。
1) install tailwindcss
2) install craco
3) edit package.json
"scripts": { "start": "craco start", "build": "craco build", "test": "craco test", "eject": "craco eject" },
4) edit craco.config.js
-
Bootstrap5
可能更受欢迎一些~ 用法与传统的一样。
Bootstrap是美国Twitter公司的设计师Mark Otto和Jacob Thornton合作基于HTML、CSS、JavaScript 开发的简洁、直观、强悍的前端开发框架,使得 Web 开发更加快捷。
Bootstrap提供了优雅的HTML和CSS规范,它即是由动态CSS语言Less写成,就是个“界面工具集”。
关于bootstrap文件包简单介绍:
解释: 1. bootstrap.css 是完整的bootstrap样式表,未经压缩过的,可供开发的时候进行调试用 2. bootstrap.min.css 是经过压缩后的bootstrap样式表,内容和bootstrap.css完全一样,但是把中间不必要的空格之类的东西都删掉了,所以文件大小会比bootstrap.css小,可以在部署网站的时候引用,如果引用了这个文件,就没必要引用bootstrap.css了 3. bootstrap-responsive.css 这个是在对bootstrap框架应用了响应式布局之后所需要的CSS样式表,如果你的网站项目不准备做响应式设计,就不需要引用这个CSS。 4. bootstrap-responsive.min.css 和bootstrap.min.css的作用是一样的,是bootstrap-responsive.css的压缩版 5. bootstrap.js 这个是bootstrap的灵魂所在,是bootstrap的所有js指令的集合,你看到bootstrap里面所有的js效果,都是由这个文件控制的,这个文件也是一个未经压缩的版本,供开发的时候进行调试用 6. bootstrap.min.js 是bootstrap.js的压缩版,内容和bootstrap.js一样的,但是文件大小会小很多,在部署网站的时候就可以不引用bootstrap.js,而换成引用这个文件了~~
利用 BootCDN 写组件 - CDN 加速服务,稳定、快速、免费的前端开源项目 CDN 加速服务。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="theme-color" content="#000000"> <!-- manifest.json provides metadata used when your web app is added to the homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/ --> <link rel="manifest" href="%PUBLIC_URL%/manifest.json"> <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico"> <link href="https://cdn.bootcss.com/bootstrap/4.0.0-beta.2/css/bootstrap.css" rel="stylesheet"> // insert this url.
JSX
-
一段最简单的主组件代码
# ------------- # JSX: js+html # ------------- import React from 'react';
import './APP.css';
function App() { return ( <div className="App"> <h1>I love React.</h1> </div> ); # 版本二,js的写法,下面的虽然正规,但理解不够直接~ return React.createElement('div', { className: 'text-danger' }, React.createElement('h1', {}, 'I love React.')) } export default App;
第一个 React 组件
创建组件
1) 定义了一个小组件。
# ---------------------------- # Define ItemDetail Component # ---------------------------- # Create src/components/ItemDetail.js import React from 'react'; const ItemDetail = () => { return ( <div>ItemDetail</div> ) } export default ItemDetail;
2) 导入组件,使用组件。
# -------------------------- # Use ItemDetail Component # -------------------------- import React from 'react'; import ItemDetail from './components/ItemDetail'; function App() { return ( <div className="App"> <h1>I love React.</h1> <hr /> <ItemDetail></ItemDetail> </div> ); } export default App;
传参
调用传入参数。
return ( <div className="App"> <h1>I love React.</h1> <hr /> <ItemDetail2> title={itemData.title} image={itemData.image} content={itemData.content} link={itemData.link} </ItemDetail2> </div> ); }
更加模块化的写法,渲染多个卡片。
const listItems = dataList.map((itemData, index) => <ItemDetail2 title={itemData.title} image={itemData.image} content={itemData.content} link={itemData.link} ></ItemDetail2> ); return ( <div className="App"> <h1>I love React.</h1> <hr /> <div className="d-flex"> {listItems}
</div> </div> ); }
通过 props 获得参数,进入组件内部。
以上是创建了一个卡片的组件。
在 react 脚手架创建的项目中 public 文件夹默认有一个root
根节点,最后完成的代码都会放到<div id="root"></div>
节点中,无论是在函数组件的return
中还是类组件的render()
中的 JSX 语法必须有一个标签包裹,使用 div 标签会在页面中正式的插入这个标签,可能会在某些情况下形成困扰,所以 react 提供另外一个占位符Fragment
。使用时只需要包裹在 JSX 语法的最外层即可。
import React, { Fragment } from 'react' // 占位符,技巧
响应(点击)事件
Ref: https://zh-hans.react.dev/learn/responding-to-events
-
点击按钮事件
export default function Button() { function handleClick(event) { alert('你点击了我!'); }
// 上面程序,下面是html return ( <button onClick={handleClick}> 点我 </button> ); }
-
其他事件
Goto: https://zh-hans.legacy.reactjs.org/docs/events.html#mouse-events
"有状态"的变量
下面的,不仅定义了value,返回的是一套东西:变量 + method。
let ItemTitle = "jinglingbaokement" // 注意:上下的区别 let [ItemTitle, setItemTitle] = useState("jinglingbaokement") const_btn_click = (event) => { console.log('btn_click', Math.random()) setItemTitle("ke ai bao ke meng.") }
return (
<Fragment>
<h5 className="card-title">{ItemTitle}</h5>
</Fragment>
)
React 组件 API,除了useState,还有其他6种方法:
设置状态:setState
替换状态:replaceState
设置属性:setProps
替换属性:replaceProps
强制更新:forceUpdate
获取DOM节点:findDOMNode
判断组件挂载状态:isMounted
动态 style 样式
与html时一样的。
const [FLG, setFLG] = useState(true); return ( <Fragment> <h1 style = ({ color: FLG ? 'red': 'blue', backgroundColor: FLG ? 'yellow' : 'gray', })>MyStyle</h1> </Fragment> )
一般而言,我们直接使用 className of BootStrap,而非如上最为初级的style。
<h1 className={FLG ? 'text-primary bg-light': 'text-danger bg-warning'}>MyStyle</h1>
创建一个表单
表单的数据如何收集?
用户输入应当保存在 变量 or state 中。
用户输入的响应事件,将“改变的部分”及时地update into var or state。
import React, { Fragment, useState } from 'react'; const AwsForm = () => {
const [txtAccessKeyID, setAccessKeyID] = useState('')
const txtAccessKeyID_onchange = (event) => { // 响应用户的事件 setAccessKeyID(event.target.value) // --> 赋值的地方 } const btn_click = (event) => { console.log(txtAccessKeyID) } return (
// 有了双向绑定的效果 <input type="text" className="form-control", id="txtAccessKeyID" value={txtAccessKeyID} onChange={txtAccessKeyID_onchange}> ) }
使用 ref 引用 useRef
Ref: https://zh-hans.reactjs.org/docs/refs-and-the-dom.html
Refs 提供了一种方式,允许我们访问在 render 方法中创建的 DOM 节点或 React 元素。
在典型的 React 数据流中,props 是父组件与子组件交互的唯一方式。要修改一个子组件,你需要使用新的 props 来重新渲染它。但是,在某些情况下,你需要在典型数据流之外强制修改子组件。被修改的子组件可能是一个 React 组件的实例,也可能是一个 DOM 元素。对于这两种情况,React 都提供了解决办法。
-
-
管理焦点,文本选择或媒体播放。
-
触发强制动画。
-
集成第三方 DOM 库
-
切勿过度使用 Refs
可以使用状态state实现的功能,尽量采用状态实现,而不要使用 ref。
import React, { Fragment, useRef } from 'react'; const AwsForm2 = () => { const refAccessKeyID = useRef(); const refSecretAccessKey = useRef(); const refRegionID = useRef(); const btn_click = (event) => { console.log(refAccessKeyID.current.value) console.log(refSecretAccessKey.current.value) console.log(refRegionID.current.value) }
... ... <input type="text" className="form-control" id="txtAccessKeyID" ref={refAccessKeyID} /> <input type="password" className="form-control" id="txtSecretAccessKey" ref={refSecretAccessKey} /> <select className="form-select font12" id="selectRegionID" ref={refRegionID}>
发送表单
在下图的基础上,扩充 handlerAppDataEvent方法。
重写 handlerAppDataEvent() by Fetch API.
const handlerAppDataEvent = async (appdata) => { const postdata = JSON.stringify({ accessKeyID: appdata.accessKeyID, secretAccessKey: appdata.secretAccessKey, secretRegionID: appdata.regionID, }); const res = await fetch('http://127.0.0.1:8080/json', { method: 'POST', body: postdata, headers: { 'user-agent': 'Mozilla/99.0 MDN Example', 'content-type': 'application/json' }, }) const data = await res.json(); setMessage(JSON.stringify(data.body, {}, 2)); }
Todolist 小组件
其实就是写一个todolist的组件。
父组件的方法删去父组件传递来的ID。
import React from 'react'; const TodoDetailList = (props) => { return ( <div key={props.id} className="d-flex py-2"> <div className="me-auto fs-3">{props.text}</div> <div> <button className="btn btn-danger btn-sm" onClick={() => props.onDelete(props.id)} Delete </button> </div> </div> ) } export default TodoDetailList;
删除即是父组件中对state操作。
const [mytodolist, setMytodolist] = useState([]);
const btn_del_click = (itemId) => { setMytodolist(prevList => { const newList = prevList.filter(item => item.id != itemId); return newList; }); }