React.js 基础用法

113 阅读4分钟

本文主题: 掌握 React.js 项目搭建和基础用法

包括: React 的发展过程 | React 项目创建 |

React 基础能力: 组件 | State | Props | 组件通信 | 条件渲染 | 列表渲染

一、React 浅析

1.1 传统方式下前端是如何构建用户界面的?

JS本质 - 浏览器脚本

  • JS 可以去操作 DOM, 可以去增删改查 DOM。
  • JS 是一种可以操作DOM的动态语言。

1.2 基于 JavaScript 创建 DOM

任意一种标签元素, 都可以通过一个 JS 的函数来创建。封装一系列方法来完成该功能。

createElemet 的实现方式

function createElement(tag, attrs = {}, ...children) {
    // 创建一个新元素
    const element = document.createElement(tag);

    // 设置元素的属性
    for (let key in attrs) {
        if (key.startsWith('on') && typeof attrs[key] === 'function') {
            // 如果属性是一个事件监听器 (如 'onclick')
            element.addEventListener(key.substring(2).toLowerCase(), attrs[key]);
        } else if (key === 'style' && typeof attrs[key] === 'object') {
            // 如果属性是样式对象
            Object.assign(element.style, attrs[key]);
        } else {
            // 其他属性
            element.setAttribute(key, attrs[key]);
        }
    }

    // 添加子元素
    children.forEach(child => {
        if (typeof child === 'string') {
            // 如果子元素是文本节点
            element.appendChild(document.createTextNode(child));
        } else if (child instanceof Node) {
            // 如果子元素是 DOM 节点
            element.appendChild(child);
        }
    });

    return element;
}

// 使用示例
const myElement = createElement(
    'div',
    { id: 'myDiv', class: 'container', style: { color: 'red', backgroundColor: 'black' }, onclick: () => alert('Hello!') },
    createElement('h1', {}, 'Hello World!'),
    'Some text here',
    createElement('p', {}, 'This is a paragraph.')
);

document.body.appendChild(myElement);

1.3 按照这种逻辑我们是不是可以这样 - React 代码

<div id="app">
    <h1>Hello!</h1>
    <h2>This is</h2>
    <h3>Me</h3>
</div>
createElement("div",{id:"app"}, 
    createElement("h1",{},"Hello!")
    createElement("h2",{},"This is<")
    createElement("h3",{},"Me")
)



function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
      </header>
    </div>
  );
}

export default App;

// babel/preset-react

function App() {
  return React.createElement("div", {
    className: "App"
  }, React.createElement("header", {
    className: "App-header"
  }, React.createElement("img", {
    src: logo,
    className: "App-logo",
    alt: "logo"
  }), React.createElement("p", null, "Edit ", React.createElement("code", null, "src/App.js"), " and save to reload.")));
}

export default App;

1.3.1 使用 babel 转换代码: babeljs.io/ try it out

image.png

1.4 对比分析React.createElement和我们的createELement有什么区别?

image.png

1.5 前端在干什么?

用户交互 → 页面更新

useEffect(); // 用户刷新
@click → handleClick → this.data.xxx = 'xxxx' → useState/dispatch

1.6 React 的灵活性

vue 中的 for 循环

<template v-for="item in list"></template>

react


{

list.map(item=> <span />)

}

二、创建 React 工程

npx create-react-app demo-app

npx create-react-app demo-app-ts --template typescript

npm run eject

三、React 的基础能力

3.1 子父组件

组件首字母大写

  • 从界面的视角看

    • Class 组件渲染的是 render 函数中的 return 的内容
    • Function 组件渲染的是函数本身返回的内容

3.2 State 和 Props

在 react 中, 有一个概念叫 state。

  • 如果我有一个数据, 我期望 数据改变时 去触发界面更新。

    • 我要把数据定义为 State
    • 我要使用特定的方法更新这个 State

3.2.1 类组件

setState

类组件上要使用 setState 方法

  • State 的值互相不影响
  • 第二个参数是一个 cb , 能拿到最新的 State

受控组件 Input 双向绑定

import React, {Component} from 'react'

// 类组件
export default class ClassCom extends Component {
    // 定义 State
    // 方法1: state = {}
    // 正规写法 constructor
    constructor(props){
        super(props)
        this.state = {
            number: 0,
            message: "Hello Tong"
        }
    }
    handleClick = (type) => {
        if(type === 'plus'){
            this.setState({
                number: this.state.number + 1
            }, ()=>{
                console.log('number in handleClick cb', this.state.number) // 最新的值
            }) 
        } else if(type === 'minus') {
            this.setState({
                number: this.state.number - 1
            }) 
        }
        console.log('number in handleClick', this.state.number) // 没有立马更新,用cb拿到最新值
    }
    handleChange = (e)=>{
        this.setState({
            message: e.target.value
        })
    }
    render(){
        const {message,number} = this.state
        return (
            <div>
                <h2>类组件 State的用法</h2>
                <h3>message: {message}, number {number}</h3>
                {/* 受控组件 期望 input value 和 message 一起 */}
                <input type="text" value={message} onChange={this.handleChange} />
                <button onClick={this.handleClick.bind(this,'plus')} >number 加1</button>
                <button onClick={this.handleClick.bind(this,'minus')} >number 减1</button>
            </div>
        )
    }
}

3.2.2 函数组件

useState

[state,dispatch] = useState(initState) useState 签名

  • State 作为组件的状态, 提供给 UI 渲染视图

  • dispatch 用户修改 State 的方法, 同时触发组件更新

    • Dispatch参数 可以是函数, 可以不是, 如果是函数, 就更新为函数执行的结果, 如果不是, 直接更新为值。
    • initstate: 初始值, 可以传, 也可以不传

3.2.3 Props

子父组件传值的工具

// APP.JSX
import { useState } from 'react';
import './App.css';
import ClassCom from './basic/ClassCom';
import FuncCom from './basic/FuncCom';

function App() {
  const [count, setCount] = useState(1024)
  const handleClick = ()=>{
    setCount(count => count+1)
  }
  return (
    <div className="App">
      {/* 父组件向子组件传值 */}
      <ClassCom name="我是类组件" />
      <FuncCom name="我是函数组件" count={count} onClick={handleClick} setCount={setCount} />
    </div>
  );
}

export default App;
  

// FuncCom.JSX
import React, { useState } from 'react';

// 函数组件
export default function FuncCom({name,count,onClick,setCount}) {
    // const arr = useState() => [S, Dispatch] = useState<S>(initialState: S | (() => S))
    const [number, setNumber] = useState(_=>0)
    const [message, setMsg] = useState("Hello React")

    const handleClick = (type)  =>{
        if (type === 'plus') {
            setNumber(number+1)
        } else {
            setNumber(number-1)
        } 
    }
    const handleChange = (e)=> {
        setMsg(e.target.value)
    }
    return   (
        <div>
                <p>Name: {name}</p>
                <p>Count: {count}</p>
                <h2>函数组件 UseState的用法</h2>
                <h3>message: {message}, number {number}</h3>
                {/* 受控组件 期望 input value 和 message 一起 */}
                <input type="text" value={message} onChange={handleChange} />
                <button onClick={handleClick.bind(this,'plus')} >number 加1</button>
                <button onClick={handleClick.bind(this,'minus')} >number 减1</button>
                <button onClick={()=>onClick?.()} >修改count</button>
                <button onClick={()=>setCount(v=>v+1)} >修改count</button>
           
            </div>
    )
}
// ClassCom.JSX
import React, {Component} from 'react'

// 类组件
export default class ClassCom extends Component {
    // 定义 State
    // 方法1: state = {}
    // 正规写法 constructor
    constructor(props){
        super(props)
        this.state = {
            number: 0,
            message: "Hello Tong"
        }
    }
    handleClick = (type) => {
        if(type === 'plus'){
            this.setState({
                number: this.state.number + 1
            }, ()=>{
                console.log('number in handleClick cb', this.state.number) // 最新的值
            }) 
        } else if(type === 'minus') {
            this.setState({
                number: this.state.number - 1
            }) 
        }
        console.log('number in handleClick', this.state.number) // 没有立马更新,用cb拿到最新值
    }
    handleChange = (e)=>{
        this.setState({
            message: e.target.value
        })
    }
    render(){
        const {message,number} = this.state
        return (
            <div>
                <p>{this.props.name}</p>
                <h2>类组件 State的用法</h2>
                <h3>message: {message}, number {number}</h3>
                {/* 受控组件 期望 input value 和 message 一起 */}
                <input type="text" value={message} onChange={this.handleChange} />
                <button onClick={this.handleClick.bind(this,'plus')} >number 加1</button>
                <button onClick={this.handleClick.bind(this,'minus')} >number 减1</button>
            </div>
        )
    }
}

3.3 条件渲染和列表渲染

import React from 'react';

export default function Render() {
    const list = ['山东','山西','河南','河北']
    return   (
        <div>
           <div>========</div>   
           <div>{list.length>0 ? '地名' :'nothing'}</div>
           <ul>
            {
               list.map(item=><li key={item}>{item}</li>) 
            }
           </ul>
           <div>========</div> 
        </div>
    )
}

相关网站

Create React App 中文文档: create-react-app.bootcss.com/

React 官网: react.dev/

React 中文官网: react.docschina.org/