react 知识点汇总(非常全面)

news2024/11/28 7:27:12

React 是一个用于构建用户界面的 JavaScript 库,由 Facebook 开发并维护。它的核心理念是“组件化”,即将用户界面拆分为可重用的组件。

React 的组件通常使用 JSX(JavaScript XML)。JSX 是一种 JavaScript 语法扩展,允许开发者在 JavaScript 代码中编写类似 HTML 的结构。

1、初识react

1.1 常用命令

首先安装 Nodejs,然后执行下面命令安装 react

npm i -g create-react-app
create-react-app myreact # 创建react项目

npm start # 在项目中输入,启动项目

1.2 项目结构

项目创建后有很多文件,一般我们只需保留下面的就行.

  • index.html:应用的主 HTML 文件,React 应用的根组件通常挂载在此文件中的一个
    元素上。
  • index.css:全局样式文件。
  • index.js:应用的入口文件,负责渲染根组件并将其挂载到 index.html 中的 DOM。
  • package.json: 包含项目的元数据(如名称、版本、描述等)、依赖包列表和脚本命令(如 startbuildtest)。
my-app/
├── node_modules/
├── public/
│   ├── favicon.ico
|   ├── index.html
├── src/
│   ├── index.css
│   ├── index.js
├── .gitignore
├── package.json
├── README.md
└── yarn.lock / package-lock.json

2、基本知识点

1. extends Component

在 React 中,extends Component 是用来创建类组件的方式。React 的类组件通过继承 React.Component 来获得组件的基本功能,如状态管理和生命周期方法。以下是一个简单的例子:

import React, { Component } from 'react';

class MyComponent extends Component {
  render() {
    return <h1>Hello, World!</h1>;
  }
}
  • Component:是 React 提供的基类,包含了生命周期方法(如 componentDidMountcomponentDidUpdate 等)和其他基本功能。

  • render 方法:每个类组件必须实现的一个方法,用于描述 UI 如何渲染。每当组件的 stateprops 更新时,render 方法会被调用。

    render() {
      return (
        <div>
          <h1>Hello, {this.props.name}!</h1>
        </div>
      );
    }
    
    • 返回值render 方法可以返回一个单一的元素、多个元素(需要用一个父元素包裹)或者 null

2. React.Fragment

React.Fragment 是一个用于分组多个子元素而不添加额外 DOM 节点的工具。通常,React 要求每个组件必须返回一个单一的根元素,使用 Fragment 可以解决这个问题。示例:

import React from 'react';

class MyComponent extends Component {
  render() {
    return (
      <React.Fragment>
        <h1>Title</h1>
        <p>Some content.</p>
      </React.Fragment>
    );
  }
}
  • 语法简化:可以用 <></> 来简化 Fragment 的使用:

3. className

在 React 中,使用 className 属性来指定一个或多个 CSS 类,而不是使用 HTML 的 class 属性。这是因为 class 是 JavaScript 中的保留关键字,React 采用 className 来避免冲突。

示例:

function MyComponent() {
  return <div className="my-class">Hello, World!</div>;
}
.my-class {
  color: blue;
  font-size: 20px;
}
动态类名
function MyComponent({ isActive }) {
  return (
    <div className={`my-class ${isActive ? 'active' : ''}`}>
      Hello, World!
    </div>
  );
}

在这个例子中,如果 isActivetruediv 将具有 active 类。

4. {} 的用法

在 JSX 中,{} 用于表示 JavaScript 表达式。你可以在其中嵌入变量、函数调用和其他表达式。

示例:

const name = "Alice";

function Greeting() {
  return <h1>Hello, {name}!</h1>; // 使用 {} 插入变量
}

5 jsx 中的 css

1. 基本语法

在 JSX 中,内联样式需要使用 JavaScript 对象的形式定义。具体来说:

  • 样式属性使用驼峰命名法(camelCase)。
  • 属性值通常为字符串或数字(需要附加单位时,使用字符串)。
1.1 示例代码
const MyComponent = () => {
    const style = {
        color: 'blue',
        backgroundColor: 'lightgray',
        padding: '10px',
        fontSize: '16px',
        border: '1px solid black'
    };

    return <div style={style}>这是一个内联样式的组件</div>;
};

在这个示例中,我们定义了一个样式对象 style,并将其应用到 <div> 元素中。

2. 动态样式

内联样式的一个主要优势是可以很容易地根据组件的状态或属性动态更新样式。例如,可以根据 state 的值来改变样式:

import React, { useState } from 'react';

const DynamicStyleComponent = () => {
    const [isActive, setIsActive] = useState(false);

    const style = {
        color: isActive ? 'white' : 'black',
        backgroundColor: isActive ? 'blue' : 'gray',
        padding: '10px',
        cursor: 'pointer'
    };

    return (
        <div 
            style={style} 
            onClick={() => setIsActive(!isActive)}
        >
            {isActive ? '激活状态' : '非激活状态'}
        </div>
    );
};

在这个示例中,点击 <div> 会切换其状态,从而改变文字和背景颜色。

3. 优缺点
优点
  • 简单直接:可以快速应用样式,尤其是动态样式时。
  • 无类名冲突:因为样式是局部的,不会受到其他样式的影响。
缺点
  • 不可复用:无法将样式应用于多个组件,难以维护。
  • 性能问题:每次渲染都会创建新的对象,可能会影响性能,特别是在频繁更新的组件中。
  • 不支持伪类和媒体查询:无法使用 CSS 的伪类(如 :hover)和媒体查询,限制了样式的灵活性。

3、Componets 写法

1. React 组件的基本概念

React 组件是构成 React 应用的基本单元。它们可以是类组件或函数组件。类组件使用 ES6 类来定义,而函数组件则是简单的 JavaScript 函数。

1.1 类组件

类组件通常用于需要管理状态或使用生命周期方法的场景。

import React, { Component } from 'react';

class MyComponent extends Component {
    // 构造函数用于初始化 state
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        };
    }
    // 上面 constructor 这块的代码可以只写 state {count : 0}, 
    // 在类组件中,可以直接在类的主体中定义 state,而不必在构造函数中初始化。
    // 这种语法会自动将 state 绑定到实例上,因此不需要显式调用 super(props)。

    // 增加 count 的方法
    increment = () => {
        this.setState({ count: this.state.count + 1 });
    };

    render() {
        return (
            <div>
                <h1>{this.state.count}</h1>
                <button onClick={this.increment}>增加</button>
            </div>
        );
    }
}

export default MyComponent;
1.2 函数组件

函数组件是无状态的,可以使用 React Hooks 来管理状态和副作用。

import React, { useState } from 'react';

const MyComponent = () => {
    const [count, setCount] = useState(0); // useState Hook

    const increment = () => {
        setCount(count + 1);
    };

    return (
        <div>
            <h1>{count}</h1>
            <button onClick={increment}>增加</button>
        </div>
    );
};

export default MyComponent;

2. State 的管理

state 是组件的本地状态,用于存储组件的动态数据。当状态改变时,React 会自动重新渲染组件。

2.1 设置初始状态

在类组件中,初始状态通常在构造函数中定义;在函数组件中,可以使用 useState Hook。

2.2 修改状态

使用 this.setState(类组件)或状态更新函数(函数组件)来更新状态。重要的是,状态更新是异步的。

// 类组件
this.setState({ key: value });

// 函数组件
setCount(newCount);

3. 遍历生成元素

在状态中存储一个数组,然后通过 .map() 方法遍历生成多个元素。

3.1 类组件示例
class ListComponent extends Component {
    constructor(props) {
        super(props);
        this.state = {
            items: ['苹果', '香蕉', '橙子']
        };
    }

    render() {
        return (
            <ul>
                {this.state.items.map((item, index) => (
                    <li key={index}>{item}</li>
                ))}
            </ul>
        );
    }
}
3.2 函数组件示例
const ListComponent = () => {
    const [items, setItems] = useState(['苹果', '香蕉', '橙子']);

    return (
        <ul>
            {items.map((item, index) => (
                <li key={index}>{item}</li>
            ))}
        </ul>
    );
};

4. 函数传参

4.1 传递参数 e
class MyComponent extends Component {
  handleClick = (e) => {
    console.log(e.target);
  };

  render() {
    return (
      <button onClick={this.handleClick}>	// 传递参数 e
        Click me
      </button>
    );
  }
}
4.2 传递自定义参数
class MyComponent extends Component {
  handleClick = (param) => {
    console.log('Button clicked!', param);
  };

  render() {
    return (
      <button onClick={() => this.handleClick('Hello')}>	// 传递自定义参数
        Click me
      </button>
    );
  }
}
4.3 传递参数 e 和 自定义参数
class MyComponent extends Component {
  handleClick = (param, e) => {
    console.log('Button clicked!', param);
  };

  render() {
    return (
      <button onClick={(e) => this.handleClick('Hello', e)}>	// 传递参数
        Click me
      </button>
    );
  }
}

5. 添加、删除和更新状态

可以通过按钮或其他交互方式来添加、删除或更新状态中的元素。

5.1 添加元素
// 在类组件中
addItem = () => {
    this.setState(prevState => ({
        items: [...prevState.items, '新水果']
    }));
};

// 在函数组件中
const addItem = () => {
    setItems([...items, '新水果']);
};
5.2 删除元素
// 在类组件中
removeItem = index => {
    this.setState(prevState => ({
        items: prevState.items.filter((_, i) => i !== index)
    }));
};

// 在函数组件中
const removeItem = index => {
    setItems(items.filter((_, i) => i !== index));
};

6. 受控表单绑定

import React, { useState } from 'react';

function ControlledForm() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    alert(`Name: ${name}, Email: ${email}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>
          Name:
          <input
            type="text"
            value={name}	// 把 name 赋值给value
            onChange={(e) => setName(e.target.value)}		// name 绑定上target.value
          />
        </label>
      </div>
      <div>
        <label>
          Email:
          <input
            type="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
        </label>
      </div>
      <button type="submit">Submit</button>
    </form>
  );
}

export default ControlledForm;

7. 获取dom元素

1. 函数组件

可以通过 useRef 创建 refs:

import React, { useRef } from 'react';

function FocusInput() {
  const inputRef = useRef(null);	

  const handleFocus = () => {
    inputRef.current.focus(); // 获取到的 DOM 元素调用 focus 方法
  };

  return (
    <div>
      <input type="text" ref={inputRef} />
      <button onClick={handleFocus}>Focus the input</button>
    </div>
  );
}

export default FocusInput;
  • useRef: 创建一个 ref,用于存储对 DOM 元素的引用。
  • ref 属性: 将 ref 赋值给要获取的元素,例如 <input>
  • 访问 DOM 元素: 通过 inputRef.current 来访问 DOM 元素。
2. 类组件

可以通过 React.createRef() 创建 refs:

import React, { Component } from 'react';

class FocusInput extends Component {
  constructor(props) {
    super(props);
    this.inputRef = React.createRef();
  }

  handleFocus = () => {
    this.inputRef.current.focus();
  };

  render() {
    return (
      <div>
        <input type="text" ref={this.inputRef} />
        <button onClick={this.handleFocus}>Focus the input</button>
      </div>
    );
  }
}

export default FocusInput;

4、组件之间传递数据

子组件接收到的 props 是不可变的。如果需要修改 props 中的数据,应该通过父组件来管理状态并传递更新的值。

1 - 4 都是 父传子, 5 是 子传父

1. 传递常见数据类型(类组件写法)

在父组件的 state 中存储基本数据类型,并通过 props 传递给子组件。

父组件

import React, { Component } from 'react';
import ChildComponent from './ChildComponent';

class ParentComponent extends Component {
  state = {
  	// 基本数据类型
    message: 'Hello from Parent!',
    numberValue: 42,
    boolValue: true,
    
    user: {	// 对象
      name: 'Alice',
      age: 30,
    },
    
  };

  handleAlert = () => {	// 方法
    alert('Hello from Parent!');
  };

  updateBoolValue = () => {
    this.setState(prevState => ({ boolValue: !prevState.boolValue }));
  };

  render() {
    return (
      <div>
        <h1>Parent Component</h1>
        <ChildComponent
          message={this.state.message}
          number={this.state.numberValue}
          isTrue={this.state.boolValue}
          
          user={this.state.user}	// 对象
          showAlert={this.handleAlert}	// 方法
        />
        <button onClick={this.updateBoolValue}>Toggle Boolean</button>
      </div>
    );
  }
}

export default ParentComponent;

子组件

import React, { Component } from 'react';

class ChildComponent extends Component {
  render() {
    return (
      <div>
        <h2>Child Component</h2>
        <p>{this.props.message}</p>
        <p>Number: {this.props.number}</p>
        <p>Boolean: {this.props.isTrue ? 'True' : 'False'}</p>
        
        <ChildComponent user={this.state.user} />	// 对象
      </div>
    );
  }
}

export default ChildComponent;

2. 传递常见数据类型(函数组件写法)

父组件

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

const ParentComponent = () => {
  const [message] = useState('Hello from Parent!');
  const [numberValue] = useState(42);
  const [boolValue, setBoolValue] = useState(true);
  const [user] = useState({
    name: 'Alice',
    age: 30,
  });

  const handleAlert = () => {
    alert('Hello from Parent!');
  };

  const updateBoolValue = () => {
    setBoolValue(prev => !prev);
  };

  return (
    <div>
      <h1>Parent Component</h1>
      <ChildComponent
        message={message}
        number={numberValue}
        isTrue={boolValue}
        user={user}
        showAlert={handleAlert}
      />
      <button onClick={updateBoolValue}>Toggle Boolean</button>
    </div>
  );
};

export default ParentComponent;

子组件

import React from 'react';

const ChildComponent = ({ message, number, isTrue, user }) => {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{message}</p>
      <p>Number: {number}</p>
      <p>Boolean: {isTrue ? 'True' : 'False'}</p>
      <p>User: {user.name}, Age: {user.age}</p> {/* 对象 */}
    </div>
  );
};

export default ChildComponent;

说明

  • 使用 useState 来管理状态。
  • 通过解构 props 直接在函数参数中获取需要的值。
  • 保持功能和逻辑不变,实现了相同的父子组件传值。

3. 传递多个 HTML 结构(类组件)

父组件将多个 JSX 元素传递给子组件,通过 props.children 访问这些元素。

import React, { Component } from 'react';
import ChildComponent from './ChildComponent';

class ParentComponent extends Component {
  render() {
    return (
      <div>
        <h1>Parent Component</h1>
        <ChildComponent>	//  把 html 写在组件子组件当中
          <p>This is the first custom content!</p>
          <p>This is the second custom content!</p>
          <h3>This is a header as custom content!</h3>
        </ChildComponent>
      </div>
    );
  }
}

export default ParentComponent;

子组件

在子组件中,我们可以通过 React.Children.map 或者 this.props.children 分别处理传递过来的多个元素。

import React, { Component } from 'react';

class ChildComponent extends Component {
  render() {
    return (
      <div>
        <h2>Child Component</h2>	// children数组中包含了父组件传递的 html
        {React.Children.map(this.props.children, (child, index) => (
          <div key={index}>{child}</div>
        ))}
      </div>
    );
  }
}

export default ChildComponent;

4. 传递多个 HTML 结构(函数组件)

父组件

import React from 'react';
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
  return (
    <div>
      <h1>Parent Component</h1>
      <ChildComponent>
        <p>This is the first custom content!</p>
        <p>This is the second custom content!</p>
        <h3>This is a header as custom content!</h3>
      </ChildComponent>
    </div>
  );
};

export default ParentComponent;

子组件

import React from 'react';

const ChildComponent = ({ children }) => {
  return (
    <div>
      <h2>Child Component</h2>
      {React.Children.map(children, (child, index) => (
        <div key={index}>{child}</div>
      ))}
    </div>
  );
};

export default ChildComponent;

说明

  • 父组件: 使用函数组件,并将多个 JSX 元素作为子组件的内容传递。
  • 子组件: 通过解构 props 获取 children,并使用 React.Children.map 迭代处理每个子元素。

5. 子传父

父组件

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

const ParentComponent = () => {
  const [dataFromChild, setDataFromChild] = useState('');

  const handleDataChange = (data) => {
    setDataFromChild(data);
  };

  return (
    <div>
      <h1>Parent Component</h1>
      <p>Data from Child: {dataFromChild}</p>
      <ChildComponent onDataChange={handleDataChange} />
    </div>
  );
};

export default ParentComponent;

子组件

import React from 'react';

const ChildComponent = ({ onDataChange }) => {
  const sendDataToParent = () => {
    const data = 'Hello from Child!';
    onDataChange(data); // 调用父组件传来的函数
  };

  return (
    <div>
      <h2>Child Component</h2>
      <button onClick={sendDataToParent}>Send Data to Parent</button>
    </div>
  );
};

export default ChildComponent;

说明

  1. 父组件: ParentComponent 使用 useState 来存储从子组件接收到的数据,并定义一个 handleDataChange 函数来更新状态。
  2. 子组件: ChildComponent 接收 onDataChange 函数作为 prop,点击按钮时调用该函数将数据发送给父组件。

5、生命周期

  • 挂载阶段

    • constructor()
    • render()
    • componentDidMount()
  • 更新阶段

    • getDerivedStateFromProps()
    • shouldComponentUpdate()
    • render()
    • componentDidUpdate()
  • 卸载阶段

    • componentWillUnmount()

1. 挂载(Mount)

当组件被创建并插入到 DOM 中时,进入挂载阶段。执行顺序如下:

  1. constructor():构造函数用于初始化状态和绑定方法。
  2. render():返回要渲染的 JSX,决定组件的结构。
  3. componentDidMount():组件挂载后调用,适合进行 API 请求或添加事件监听。

2. 更新(Update)

当组件的状态或属性发生变化时,组件会重新渲染,进入更新阶段。执行顺序如下:

  1. render():重新渲染组件。
  2. getDerivedStateFromProps(nextProps, prevState):在渲染前调用,可以根据新 props 更新 state。
  3. shouldComponentUpdate(nextProps, nextState):用于控制组件是否重新渲染,返回 truefalse
  4. componentDidUpdate(prevProps, prevState):组件更新后调用,可以根据上一个状态或属性执行副作用。

3. 卸载(Unmount)

当组件从 DOM 中移除时,进入卸载阶段。执行顺序如下:

  1. componentWillUnmount():组件卸载前调用,适合清理资源(如取消网络请求或移除事件监听)。

4. 使用 Hook 的方式

在函数组件中,可以使用 Hook 来实现类似的生命周期效果:

  • useEffect:相当于 componentDidMountcomponentDidUpdate,可以用于处理副作用。
import React, { useEffect, useState } from 'react';

const MyComponent = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // 组件挂载时执行
    console.log('Component mounted');

    // 组件更新时执行
    return () => {
      // 组件卸载时清理
      console.log('Component unmounted');
    };
  }, [count]); // 依赖数组,count 变化时执行

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};

6、 路由

1. 基础概念

路由(Routing):在单页应用(SPA)中,路由用于管理不同视图或页面之间的导航。当用户点击链接或按钮时,路由会拦截这些操作,并根据 URL 的变化加载相应的组件,而不需要重新加载整个页面。

React Router:这是最流行的 React 路由库,它提供了灵活的路由功能。React Router 通过组件化的方式来定义和管理路由。

2. 常用组件

React Router 提供了几个核心组件,下面是一些常用的组件及其用途:

  • BrowserRouter:这个组件提供了基于 HTML5 的历史记录的路由。它通常包裹在应用的根组件外部。

    import { BrowserRouter } from 'react-router-dom';
    
    function App() {
      return (
        <BrowserRouter>
          {/* 其他组件 */}
        </BrowserRouter>
      );
    }
    
  • Route:用于定义路由的组件。它接受 path 属性来指定匹配的 URL,以及 element 属性来指定渲染的组件。

    import { Route } from 'react-router-dom';
    
    <Route path="/about" element={<About />} />
    
  • Routes:用来包裹多个 Route 组件,确保只有一个匹配的路由被渲染。

    import { Routes } from 'react-router-dom';
    
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="/about" element={<About />} />
    </Routes>
    
  • Link:用于在应用中创建导航链接的组件。它类似于 HTML 的 <a> 标签,但使用的是客户端路由。

    import { Link } from 'react-router-dom';
    
    <Link to="/about">About</Link>
    
  • Navigate:用于在组件中进行重定向。

    import { Navigate } from 'react-router-dom';
    
    <Navigate to="/home" />
    

3. 路由配置

配置路由通常涉及创建一个路由表,定义各个路由及其对应的组件。以下是一个简单的示例,展示如何在 React 应用中配置路由。

import React from 'react';
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';

// 导入页面组件
import Home from './Home';
import About from './About';
import NotFound from './NotFound';

function App() {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>
      </nav>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        {/* 404 页面 */}
        <Route path="*" element={<NotFound />} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

4. 嵌套路由 及 路由守卫、404

嵌套路由允许你在某个父路由的组件内部定义子路由。这样,你可以在父路由的页面中渲染子路由对应的内容。

import { Routes, Route, Link } from 'react-router-dom';

function Users() {
  return (
    <div>
      <h2>Users</h2>
      <Link to="1">User 1</Link>
      <Link to="2">User 2</Link>
      <Routes>
        <Route path=":userId" element={<UserProfile />} />
      </Routes>
    </div>
  );
}

function UserProfile() {
  const { userId } = useParams();
  return <h3>User Profile for User ID: {userId}</h3>;
}

路由守卫

路由保护可以确保只有特定条件下(例如用户登录后)才能访问某些路由。可以通过创建一个高阶组件(HOC)来实现。

function ProtectedRoute({ element, isAuthenticated }) {
  return isAuthenticated ? element : <Navigate to="/login" />;
}

// 使用
<Routes>
  <Route path="/dashboard" element={<ProtectedRoute element={<Dashboard />} isAuthenticated={isLoggedIn} />} />
</Routes>

404 页面处理

可以使用通配符路由 * 来处理未匹配的路径,并显示 404 页面。

<Route path="*" element={<NotFound />} />

5. 动态路由(match)

动态路由允许你在路径中使用参数,这样可以在 URL 中捕获动态值。例如,展示用户信息的页面。

<Route path="/users/:userId" element={<UserProfile />} />
类组件中

使用 URL 参数,可以使用 withRouter 高阶组件来获取路由的 props,包括 matchlocationhistory 对象。

使用 withRouter 获取 URL 参数

import React from 'react';
import { withRouter } from 'react-router-dom';

class UserProfile extends React.Component {
  render() {
    // 从 props 中获取 match 对象
    const { match } = this.props;
    const userId = match.params.userId; // 获取 URL 参数

    return <div>User ID: {userId}</div>;
  }
}

// 使用 withRouter 将 UserProfile 包装起来
export default withRouter(UserProfile);

关键点

  • withRouter 是一个高阶组件,它将路由的相关信息作为 props 传递给被包装的组件。
  • match.params 中包含了 URL 中的动态参数,像这里的 userId

确保在路由配置中使用 UserProfile 组件时,像这样设置路由:

<Route path="/users/:userId" element={<UserProfile />} />
函数组件

直接使用 useParams 来获取 URL 参数:

import { useParams } from 'react-router-dom';

function UserProfile() {
  const { userId } = useParams();
  return <div>User ID: {userId}</div>;
}

6. 获取 修改 查询字符串(location)

https://example.com/users?userId=123&userName=Alice

1. 类组件获取查询字符串参数

在类组件中,我们通常使用 withRouter 高阶组件来访问路由相关的信息,包括查询字符串。

示例代码

import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';

class QueryParamsClassComponent extends Component {
  render() {
    const { location } = this.props; // 从 props 中获取 location 对象
    const searchParams = new URLSearchParams(location.search); // 创建 URLSearchParams 对象

    // 获取具体的参数
    const userId = searchParams.get('userId'); // 获取 userId 参数
    const name = searchParams.get('name'); // 获取 name 参数
    // searchParams。set('userId', '456'); // 修改或添加 userId 参数
    // searchParams.set('name', 'Alice'); // 修改或添加 name 参数

    return (
      <div>
        <h1>Query Parameters</h1>
        <p>User ID: {userId}</p>
        <p>Name: {name}</p>
      </div>
    );
  }
}

export default withRouter(QueryParamsClassComponent); // 使用 withRouter 包裹类组件

代码解析

  1. 引入 withRouter:首先需要引入 withRouter,它使得组件可以访问路由的 props。
  2. 访问 location 对象:在 render 方法中,从 this.props 中获取 location 对象。
  3. 使用 URLSearchParams
    • new URLSearchParams(location.search) 创建一个 URLSearchParams 对象,location.search 包含查询字符串(包括 ?)。
    • 通过 get 方法提取具体的参数值,例如 userIdname
  4. 渲染参数:在组件的 JSX 中渲染这些参数。
2. 函数组件获取查询字符串参数

在函数组件中,我们可以使用 useLocation Hook 来获取路由信息,包括查询字符串。

示例代码

import React from 'react';
import { useLocation } from 'react-router-dom';

const QueryParamsFunctionComponent = () => {
  const location = useLocation(); // 使用 useLocation 获取 location 对象
  const searchParams = new URLSearchParams(location.search); // 创建 URLSearchParams 对象

  // 获取具体的参数
  const userId = searchParams.get('userId'); // 获取 userId 参数
  const name = searchParams.get('name'); // 获取 name 参数
  //searchParams.get('userId'); // 获取 userId 参数
  //searchParams.get('name'); // 获取 name 参数

  return (
    <div>
      <h1>Query Parameters</h1>
      <p>User ID: {userId}</p>
      <p>Name: {name}</p>
    </div>
  );
};

export default QueryParamsFunctionComponent; // 直接导出函数组件

代码解析

  1. 引入 useLocation:引入 useLocation Hook。
  2. 调用 useLocation:在函数组件中调用 useLocation(),它返回当前路由的 location 对象。
  3. 使用 URLSearchParams
    • new URLSearchParams(location.search) 创建一个 URLSearchParams 对象,用于解析查询字符串。
    • 使用 get 方法提取需要的参数值。
  4. 渲染参数:在组件的 JSX 中渲染这些参数。

7、编程导航 history

1. history 对象的概念
  • 历史记录history 对象是一个 JavaScript 对象,它表示浏览器的会话历史。每当用户访问一个新的 URL 时,浏览器会将该 URL 添加到历史记录中。
  • 导航:通过 history 对象,你可以编程式地导航到不同的页面,而不是仅仅依赖于用户点击链接。
2. history 对象的常用方法

history 对象提供了多种方法来处理导航和历史记录。以下是一些常用的方法:

push(path, [state])

  • 功能:在历史记录栈中添加一个新的条目,导航到指定的路径。
  • 参数
    • path:要导航到的路径。
    • state(可选):与新路径关联的状态对象,这个对象可以在目标页面通过 location.state 访问。

示例

this.props.history.push('/home'); // 导航到 /home
this.props.history.push('/profile', { from: 'home' }); // 导航到 /profile,并传递状态

replace(path, [state])

  • 功能:替换当前的历史记录条目,导航到指定的路径,而不是添加一个新的条目。
  • 参数:同 push 方法。

示例

this.props.history.replace('/login'); // 用 /login 替换当前的历史条目

go(n)

  • 功能:根据历史记录栈中的位置导航。
  • 参数
    • n:要导航的相对位置(正数表示向前,负数表示向后)。

示例

this.props.history.go(-1); // 返回到上一页
this.props.history.go(2); // 前进两页

goBack() 返回到上一页,等同于 go(-1)

goForward() 前进到下一页,等同于 go(1)

3. 在 React Router 中使用 history

在 React Router 中,history 对象通常是通过 withRouter 高阶组件或在函数组件中通过 useNavigateuseLocation Hook 访问的。

类组件使用 withRouter

import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';

class MyComponent extends Component {
  handleNavigation = () => {
    this.props.history.push('/home'); // 使用 history 导航
  };

  render() {
    return <button onClick={this.handleNavigation}>Go to Home</button>;
  }
}

export default withRouter(MyComponent); // 使用 withRouter 包裹组件

函数组件使用 useNavigate

在 React Router v6 及以上版本中,推荐使用 useNavigate Hook 来获取 navigate 函数。

import React from 'react';
import { useNavigate } from 'react-router-dom';

const MyFunctionComponent = () => {
  const navigate = useNavigate();

  const handleNavigation = () => {
    navigate('/home'); // 使用 navigate 导航
  };

  return <button onClick={handleNavigation}>Go to Home</button>;
};

export default MyFunctionComponent;

8、子组件的路由 Outlet

// App.js
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import UserProfile from './UserProfile';
import UserSettings from './UserSettings';
import UserActivity from './UserActivity';

const App = () => {
  return (
    <Router>
      <Routes>
        <Route path="/users/*" element={<UserProfile />}>
          <Route path="settings" element={<UserSettings />} />
          <Route path="activity" element={<UserActivity />} />
        </Route>
      </Routes>
    </Router>
  );
};

export default App;

// UserProfile.js
import React from 'react';
import { Link, Outlet } from 'react-router-dom';

const UserProfile = () => {
  return (
    <div>
      <h1>User Profile</h1>
      <nav>
        <ul>
          <li>
            <Link to="settings">Settings</Link>
          </li>
          <li>
            <Link to="activity">Activity</Link>
          </li>
        </ul>
      </nav>
      <Outlet /> {/* 渲染匹配的子路由 */}		// 路由
    </div>
  );
};

export default UserProfile;

// UserSettings.js
import React from 'react';

const UserSettings = () => {
  return <h2>User Settings</h2>;
};

export default UserSettings;

// UserActivity.js
import React from 'react';

const UserActivity = () => {
  return <h2>User Activity</h2>;
};

export default UserActivity;

7、redux 集中状态管理

Redux.createStore 是 Redux 的传统方式,用于创建 Redux store。

Redux.createStore

  1. 导入 Redux:
import { createStore } from 'redux';
  1. 定义初始状态:
const initialState = {
  todos: [],
};
  1. 创建 Reducer:

Reducer 是一个纯函数,接受当前状态和 action,并返回新的状态。

const todoReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return { ...state, todos: [...state.todos, action.payload] };
    default:
      return state;
  }
};
  1. 创建 Store:

使用 createStore 创建 store,并传入 reducer。

const store = createStore(todoReducer);
  1. 使用 Store:

可以使用 store.getState() 获取当前状态,使用 store.dispatch(action) 发送 action。

store.dispatch({ type: 'ADD_TODO', payload: { text: 'Learn Redux' } });
console.log(store.getState());

Redux Toolkit

Redux Toolkit 是官方推荐的 Redux 工具集,它简化了 Redux 的使用,包含了一些开箱即用的工具和最佳实践。使用 Redux Toolkit 可以更容易地管理状态,减少模板代码。

1. 安装

首先,安装 Redux Toolkit 和 React-Redux:

npm install @reduxjs/toolkit react-redux
2. 创建 Slice

使用 createSlice 来定义 state、reducers 和 actions。这样可以简化代码结构。

import { createSlice } from '@reduxjs/toolkit';

const todosSlice = createSlice({
  name: 'todos',
  initialState: [], // 要存的state

  // 使用 createSlice 创建 slice 时,定义的 reducer 函数会自动生成对应的 action creators。
  reducers: {
    addTodo: (state, action) => {	// state中包含所有 initialState 中的数据, 
      state.push(action.payload); // 使用 Immer 库来处理不可变状态
    },
    removeTodo: (state, action) => {
      return state.filter(todo => todo.id !== action.payload);	// payload 包含了调用时传递的参数, 可以是对象
    },
  },
});

// 导出 action
export const { addTodo, removeTodo } = todosSlice.actions;

// 导出 reducer
export default todosSlice.reducer;
3. 配置 Store

使用 configureStore 来创建 store,它会自动添加 Redux DevTools 支持和中间件。

import { configureStore } from '@reduxjs/toolkit';
import todosReducer from './todosSlice';

const store = configureStore({
  reducer: {
    todos: todosReducer,
  },
});

export default store;
4. 连接 React 和 Redux

在应用中使用 Provider 将 store 传递给组件树。

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import store from './store';
import App from './App';

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);
5. 使用 Redux State

在组件中使用 useSelectoruseDispatch 来访问状态和发起 action。

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { addTodo, removeTodo } from './todosSlice';

const TodoList = () => {
  const todos = useSelector(state => state.todos);
  const dispatch = useDispatch();

  const handleAddTodo = () => {
    const text = prompt('Enter todo:');
    const id = Date.now(); // 简单生成 ID
    dispatch(addTodo({ id, text }));
  };

  const handleRemoveTodo = (id) => {
    dispatch(removeTodo(id));
  };

  return (
    <div>
      <h1>Todo List</h1>
      <ul>
        {todos.map(todo => (
          <li key={todo.id}>
            {todo.text}
            <button onClick={() => handleRemoveTodo(todo.id)}>Remove</button>
          </li>
        ))}
      </ul>
      <button onClick={handleAddTodo}>Add Todo</button>
    </div>
  );
};

export default TodoList;
6. 处理异步操作

使用 createAsyncThunk 处理异步请求。

import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';

// 异步操作示例
export const fetchTodos = createAsyncThunk('todos/fetchTodos', async () => {
  const response = await fetch('/api/todos');
  return response.json();
});

const todosSlice = createSlice({
  name: 'todos',
  initialState: { items: [], status: 'idle' },
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchTodos.fulfilled, (state, action) => {
        state.items = action.payload;
      });
  },
});

// 导出 reducer
export default todosSlice.reducer;

8、hook

好的,我们来详细讲解一下 React Hooks,包括基本用法、常见的 Hooks 和具体的应用场景。

1、基本用法

React Hooks 是 React 16.8 引入的一种新特性,旨在让函数组件具备类组件的功能,尤其是状态管理和副作用处理。Hooks 的引入使得函数组件更加强大和灵活。

1. 使用 Hooks 的规则
  • 只能在函数组件或自定义 Hooks 中调用。 不可以在 普通 JavaScript 函数类组件 或者 条件语句 中调用。
  • 调用顺序必须一致。 React 会根据调用的顺序来追踪每个 Hook 的状态。

2、常见的 Hooks

1. useState

用于在函数组件中添加状态。

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0); // count 是状态,setCount 是更新状态的函数

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}
2. useEffect

useEffect(()=> {}, 依赖项)
在这里插入图片描述

用于处理副作用,例如数据获取、订阅等。

import React, { useState, useEffect } from 'react';

function DataFetcher() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => setData(data));

    // 可选的清理函数
    return () => {
      // 例如取消订阅
    };
  }, []); // 依赖数组,空数组意味着仅在组件挂载时执行一次

  return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
}
3. useContext

用于在组件之间共享状态,避免逐层传递 props。

import React, { createContext, useContext } from 'react';

const ThemeContext = createContext('light');

function ThemedComponent() {
  const theme = useContext(ThemeContext);

  return <div className={theme}>Current theme: {theme}</div>;
}

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <ThemedComponent />
    </ThemeContext.Provider>
  );
}
4. useReducer

用于在复杂状态逻辑中管理状态,相比 useState 更加灵活。

import React, { useReducer } from 'react';

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
    </div>
  );
}
5. 自定义 Hooks

你可以创建自己的 Hooks,复用逻辑。

import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch(url)
      .then(response => response.json())
      .then(setData)
      .catch(setError);
  }, [url]);

  return { data, error };
}

// 使用自定义 Hook
function DataFetcher({ url }) {
  const { data, error } = useFetch(url);

  if (error) return <div>Error: {error.message}</div>;
  return <div>{data ? JSON.stringify(data) : 'Loading...'}</div>;
}

3、具体的应用场景

  1. 数据获取: 使用 useEffectuseState 来从 API 获取数据。
  2. 表单管理: 使用 useState 来管理输入框的状态,并处理提交。
  3. 动画: 使用 useEffect 来设置动画的入场和离场。
  4. 订阅: 在 useEffect 中添加订阅,返回一个清理函数以取消订阅。
  5. 组合逻辑: 使用自定义 Hooks 来提取组件之间共享的逻辑。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2201281.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

house_of_muney

house_of_muney 首先介绍一下house of muney 这个利用原理&#xff1a; 在了解过_dl_runtime_resolve的前提下&#xff0c;当程序保护开了延迟绑定的时候&#xff0c;程序第一次调用相关函数的时候会执行下面的命令 push n push ModuleID jmp _dl_runtime_resolve 这里的n…

OCR+PDF解析配套前端工具开源详解!

目录 一、项目简介 TextIn为相关领域的前端开发提供了优秀的范本。 目前项目已在Github上开源&#xff01; 二、性能特色 三、安装使用 安装依赖启动项目脚本命令项目结构 四、效果展示 面对日常生活和工作中常见的OCR识别、PDF解析、翻译、校对等场景&#xff0c;配套的…

洛谷P5648

洛谷P5648 这题花了很长时间&#xff0c;是在线段树题单里找到的&#xff08; &#xff09;。有线段树做法&#xff0c;但是我感觉可能比倍增做法更难看懂。以后有空再看看吧。感觉线段树现在只会板子题&#xff0c;绿稍微难点可能就不会。 花了很久时间之后&#xff0c;就觉得…

打造直播美颜平台的关键技术:视频美颜SDK的深度解析

本篇文章&#xff0c;小编将深入解析视频美颜SDK的关键技术&#xff0c;探讨其在打造直播美颜平台中的作用。 一、视频美颜SDK的定义与功能 视频美颜SDK是一套专门为实时视频处理而设计的软件开发工具包。其主要功能包括人脸检测、肤色美化、瑕疵修复、虚化背景、实时滤镜等。…

Python对PDF文件的合并操作

在处理 PDF 文件时&#xff0c;合并多个 PDF 文件为一个单一文件或者将某个单一文件插入某个PDF文件是一个常见的需求。Python 提供了多种库来实现这一功能&#xff0c;其中 PyPDF2 是一个非常流行的选择。该库提供了简单易用的接口&#xff0c;包括 merge() 方法&#xff0c;可…

CRE6281B1 (宽VCC:8-45V PWM电源芯片)

CRE6281B1 是一款外驱功率管的高度集成的电流型PWM 控制 IC&#xff0c;为高性能、低待机功率、低成本、高效率的隔离型反激式开关电源控制器。在满载时&#xff0c;CRE6281B1工作在固定频率(65kHz)模式。在负载较低时&#xff0c;采用节能模式&#xff0c;实现较高的功率转换效…

关于Allegro导出Gerber时的槽孔问题

注意点一&#xff1a; 如果设计的板子中有 槽孔和通孔(俗称圆孔)&#xff0c;不仅要NC Drill, 还要 NC Route allegro导出的槽孔文件后缀是 .rou 圆型孔后缀 是 .drl &#xff0c;出gerber时需要看下是否有该文件。 注意点二&#xff1a; 导出钻孔文件时&#xff0c;设置参…

Hi3061M开发板——系统时钟频率

这里写目录标题 前言MCU时钟介绍PLLCRG_ConfigPLL时钟配置另附完整系统时钟结构图 前言 Hi3061M使用过程中&#xff0c;AD和APT输出&#xff0c;都需要考虑到时钟频率&#xff0c;特别是APT&#xff0c;关系到PWM的输出频率。于是就研究了下相关的时钟。 MCU时钟介绍 MCU共有…

22.1 K8S之KubeSphere实现中间件高可用集群

22.1 K8S之KubeSphere实现中间件高可用集群 一. 章节概述二. WordPress1. WordPress 简介---------------------------------------------------------------------------------------------------一. 章节概述 二. WordPress 1. WordPress 简介 创建并部署 WordPress

MySQL 数据库的性能优化方法方法有哪些?

MySQL 数据库的性能优化方法方法有哪些&#xff1f; 从开发角度来看&#xff0c;一般可以从 SQL 和库表设计两部分优化性能。 SQL 优化 根据慢sql日志&#xff0c;找出需要优化的一些sql语句。 常见优化方向&#xff1a; 避免select *&#xff0c;只查询必要的字段&#x…

62 加密算法

62 加密算法 三种加密算法分类&#xff1a; 对称加密&#xff1a;密钥只有一个&#xff0c;解密、解密都是这个密码&#xff0c;加解密速度快&#xff0c;典型的对称加密有DES、AES、RC4等非对称加密&#xff1a;密钥成对出现&#xff0c;分别为公钥和私钥&#xff0c;从公钥…

sass学习笔记(1.0)

1.使用变量 sass可以像声明变量那样进行使用&#xff0c;这样同样的样式&#xff0c;就可以使用相同的变量来提高复用。 语法为&#xff1a;$ 变量名 在界面中也可以正常的显示 当然了&#xff0c;变量之间也可以相互引用&#xff0c;比如下面 div{$_color: #d45387;$BgColo…

kibana 删除es指定数据,不是删除索引

1 查询条件查询出满足条件的数据 GET /order_header_idx_202410/_search {"from":0,"size":10,"query":{"bool":{"filter":[{"term":{"oh_tenantId":{"value":"0211000001",&…

NeuVector部署、使用与原理分析

文章目录 前言1、概述2、安装与使用2.1、安装方法2.1.1、部署NeuVector前的准备工作2.1.1.1 扩容系统交换空间2.1.1.2 Kubernetes单机部署2.1.1.2.1 部署Docker2.1.1.2.2 部署Kubectl2.1.1.2.3 部署Minikube 2.1.1.3 Helm部署 2.1.2、使用Helm部署NeuVector 2.2、使用方法2.2.1…

YOLOv5改进——添加SimAM注意力机制

目录 一、SimAM注意力机制核心代码 二、修改common.py 三、修改yolo.py ​三、建立yaml文件 四、验证 一、SimAM注意力机制核心代码 在models文件夹下新建modules文件夹&#xff0c;在modules文件夹下新建一个py文件。这里为simam.py。复制以下代码到文件里面。 import…

Mysql中创建用户并设置任何主机连接

Mysql中创建用户并设置任何主机连接 文章目录 Mysql中创建用户并设置任何主机连接背景解决方式 背景 在linux上安装mysql,默认用户是root,但是用navicat连接不了,必须要用ssh隧道连接,现在想用任何主机只要输入账号密码之后就可以连接 解决方式 #创建一个指定用户和IP链接的用…

Java:数据结构-ArrayList和顺序表(2)

一 ArrayList的使用 1.ArrayList的构造方法 第一种&#xff08;指定容量的构造方法&#xff09; 创建一个空的ArrayList&#xff0c;指定容量为initialCapacity。 public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData new Object[init…

鸿蒙微内核IPC数据结构

鸿蒙内核IPC数据结构 内核为任务之间的通信提供了多种机制&#xff0c;包含队列、事件、互斥锁、信号量等&#xff0c;其中还有Futex(用户态快速锁)&#xff0c;rwLock(读写锁)&#xff0c;signal(信号)。 队列 队列又称为消息队列&#xff0c;是一种常用于任务间通信的数据…

《ASP.NET Web Forms 实现短视频点赞功能的完整示例》

在现代Web开发中&#xff0c;实现一个动态的点赞功能是非常常见的需求。本文将详细介绍如何在ASP.NET Web Forms中实现一个视频点赞功能&#xff0c;包括前端页面的展示和后端的处理逻辑。我们将确保点赞数量能够实时更新&#xff0c;而无需刷新整个页面。 技术栈 ASP.NET We…

Java进阶之路—单元测试Juint(完整详解Juint使用以及Juin注解,附有代码+案例)

文章目录 单元测试Juint35.1 概述35.2 用法手动导包正确的使用方式 35.3 Junit常用注解 单元测试Juint 35.1 概述 针对最小功能单元编写测试代码&#xff0c;Java中最小功能单元是方法&#xff0c;因此单元测试就是针对Java方法的测试。 对部分代码进行测试。 35.2 用法 &…