[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"
  },
package.json

 

关于 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: https://zh-hans.reactjs.org/docs/refs-and-the-dom.html

Refs 提供了一种方式,允许我们访问在 render 方法中创建的 DOM 节点或 React 元素

在典型的 React 数据流中,props 是父组件与子组件交互的唯一方式。要修改一个子组件,你需要使用新的 props 来重新渲染它。但是,在某些情况下,你需要在典型数据流之外强制修改子组件。被修改的子组件可能是一个 React 组件的实例,也可能是一个 DOM 元素。对于这两种情况,React 都提供了解决办法。

何时使用 Refs

    • 管理焦点,文本选择或媒体播放。

    • 触发强制动画。

    • 集成第三方 DOM 库

避免使用 refs 来做任何可以通过声明式实现来完成的事情。

切勿过度使用 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;   }); }

 

posted @ 2022-05-06 09:02  郝壹贰叁  阅读(5)  评论(0编辑  收藏  举报