React学习

112 阅读8分钟

JSX

什么JSX

JSX是Javascript和xml的缩写,表示在js代码中编写HTML模板结构,他是React中编写UI模板的方式

export default function TodoList() {
  return (
    // 这不起作用!
    <h1>海蒂·拉玛的待办事项</h1>
    <img 
      src="https://i.imgur.com/yXOvdOSs.jpg" 
      alt="Hedy Lamarr" 
      class="photo"
    >
    <ul>
      <li>发明一种新式交通信号灯
      <li>排练一个电影场景
      <li>改进频谱技术
    </ul>
  );
}

JSX使用规则

  1. 只能返回一个根元素
  2. 标签必须闭合
  3. 使用驼峰式命名法,给大部分属性命名
  4. 在JSX中通过大括号引用Javascript变量、函数、对象

State

使用useState Hook添加state变量,state 完全私有于声明它的组件

import { useState } from 'react';
const [index, setIndex] = useState(0);

useState 的唯一参数是 state 变量的初始值,每次你的组件渲染时,useState 都会给你一个包含两个值的数组:

  1. state 变量 (index) 会保存上次渲染的值。
  2. state setter 函数 (setIndex) 可以更新 state 变量并触发 React 重新渲染组件。

Props

将Props传递给组件

React 组件使用 props 来互相通信。每个父组件都可以提供 props 给它的子组件,从而将一些信息传递给它。包括对象、数组和函数。

  1. 如何向组件传递 props
export default function Profile() {  
    return (  
        <Avatar person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}  
        size={100}  
        />  
    );  
}
  1. 如何从组件读取props
function Avatar({ person, size }) {  
// 在这里 person 和 size 是可访问的 
}

function Avatar(props) {  
    let person = props.person;  
    let size = props.size;  
    // ...  
}
  1. 如何为props指定默认值
function Avatar({ person, size = 100 }) {  
// ...  
}
  1. 使用JSX展开语法传递props
function Profile(props) {  
    return (  
        <div className="card">  
            <Avatar {...props} />  
        </div>  
    );  
}
  1. props children属性 当把内容嵌套在子组件标签中时,父组件会自动在名为children的prop属性中接收该内容。
<Son>
    <span>111</span>
</Son>

Son组件中会有一个props.children属性。

使用Context机制跨层传递数据

在React中,Context API提供了一种在组件树中跨层传递数据的方式,而无需手动通过props逐层传递。Context机制使得数据能够在组件树中的任何位置被访问,而无需明确指定数据传递的路径。这对于需要在多个层级之间共享数据的应用非常有用。

要使用Context机制,首先需要创建一个Context对象。这可以通过调用React.createContext()来实现。这个函数返回一个Context对象,该对象具有两个属性:ProviderConsumer

Provider组件用于包裹需要共享数据的最外层组件,并通过value属性提供数据。Consumer组件用于在需要接收数据的地方读取数据。然而,在实际使用中,我们更常使用useContext这个Hook来代替Consumer组件,因为它更加方便。

下面是一个使用Context API跨层传递数据的简单示例:

import React, { createContext, useContext, useState } from 'react';  
  
// 创建一个Context对象  
const ThemeContext = createContext();  
  
// ThemeContext.Provider组件  
function ThemeProvider(props) {  
  const [theme, setTheme] = useState('light');  
  
  return (  
    <ThemeContext.Provider value={{ theme, setTheme }}>  
      {props.children}  
    </ThemeContext.Provider>  
  );  
}  
  
// 使用useContext来读取Context中的数据  
function ThemedComponent() {  
  const context = useContext(ThemeContext);  
  
  return (  
    <div>  
      <h2>Current Theme: {context.theme}</h2>  
      <button onClick={() => context.setTheme('dark')}>Switch to Dark Theme</button>  
    </div>  
  );  
}  
  
// 在App组件中使用ThemeProvider包裹根组件  
function App() {  
  return (  
    <ThemeProvider>  
      <ThemedComponent />  
    </ThemeProvider>  
  );  
}  
  
export default App;

在这个示例中,我们创建了一个名为ThemeContext的Context对象。然后,我们创建了一个ThemeProvider组件,它使用ThemeContext.Provider来提供themesetTheme这两个值。在ThemedComponent组件中,我们使用useContext(ThemeContext)来读取这些值,并显示当前的主题以及一个切换主题的按钮。

通过这样做,ThemedComponent可以在不知道themesetTheme具体来源的情况下使用它们。这使得数据传递更加灵活和可维护。

需要注意的是,Context API并不是解决所有传递数据问题的银弹。对于简单的父子组件之间的数据传递,使用props进行传递通常更加直接和清晰。Context API更适合在需要跨越多层组件传递数据时使用。

UseEffect

useEffect是React中的一个Hook,用于在函数组件中执行副作用操作。副作用是指在渲染过程中执行的非渲染相关的操作,例如数据获取、订阅、手动更改DOM、日志打印等。useEffect可以替代类组件中的生命周期方法,如componentDidMountcomponentDidUpdatecomponentWillUnmount

useEffect接受两个参数:

  1. 第一个参数是一个函数,这个函数包含你想要执行的副作用逻辑。这个函数会在组件渲染后执行,并且每次组件更新时都会重新执行(除非你提供了第二个参数)。
  2. 第二个参数是一个依赖项数组。当数组中的任何值发生变化时,副作用函数将会重新执行。如果不提供第二个参数,则副作用函数会在每次组件更新时执行。如果提供一个空数组[]作为第二个参数,则副作用函数只会在组件挂载和卸载时执行。

useEffect还有一个返回值的特性,它允许你执行一些清理操作,例如取消网络请求或清除定时器。这个返回值应该是一个函数,当组件卸载或依赖项发生变化导致副作用函数重新执行时,这个函数将被调用。

下面是一个简单的useEffect示例:

import React, { useEffect, useState } from 'react';  
  
function Example() {  
  const [count, setCount] = useState(0);  
  
  // 副作用:当组件挂载和卸载时,以及当count变化时执行  
  useEffect(() => {  
    // 在这里执行副作用,例如数据获取、订阅等  
    document.title = `You clicked ${count} times`;  
  
    // 返回一个函数用于清理  
    return () => {  
      document.title = 'React App';  
    };  
  }, [count]); // 只有当count变化时,副作用才会重新执行  
  
  return (  
    <div>  
      <p>You clicked {count} times</p>  
      <button onClick={() => setCount(count + 1)}>  
        Click me  
      </button>  
    </div>  
  );  
}

useEffect执行时机

  1. 没有依赖项,组件初始渲染和组件更新时执行
  2. 空数组依赖项,组件初始渲染执行
  3. 添加特定依赖项,组件初始渲染+特定依赖项更新时执行

useEffect清除副作用

useEffect(()=>{
    //实现副作用操作逻辑
    
    return ()=>{
        //清除副作用逻辑
    }
},[])

自定义hooks

在React中,自定义hooks是一种特殊的函数组件,它们以“use”为前缀命名,允许你在多个组件之间重用状态逻辑。通过自定义hooks,你可以将组件之间的共享逻辑提取到单独的函数中,从而提高代码的可维护性和可重用性。

下面是一个简单的示例,演示如何创建一个自定义hook:

import { useState } from 'react';  
  
// 自定义hook  
function useCounter(initialCount = 0) {  
  const [count, setCount] = useState(initialCount);  
  
  const increment = () => {  
    setCount(count + 1);  
  };  
  
  const decrement = () => {  
    setCount(count - 1);  
  };  
  
  return [count, increment, decrement];  
}  
  
// 使用自定义hook的组件  
function MyComponent() {  
  const [count, increment, decrement] = useCounter(0);  
  return (  
    <div>  
      <p>Count: {count}</p>  
      <button onClick={increment}>Increment</button>  
      <button onClick={decrement}>Decrement</button>  
    </div>  
  );  
}

在上面的示例中,我们创建了一个名为useCounter的自定义hook。这个hook使用useState来管理一个计数器的状态,并提供incrementdecrement两个函数来修改计数器的值。然后,在MyComponent组件中,我们使用useCounter来获取计数器的状态和控制函数,并在组件的渲染中使用它们。

自定义hooks的命名约定是以“use”为前缀,并且它们应该只依赖于React的API和其他的自定义hooks。这样,它们就可以在多个组件之间重用,并保持组件之间的逻辑分离。

通过自定义hooks,你可以将复杂的逻辑封装在单独的函数中,并在需要的地方重复使用它们。这有助于减少代码冗余,提高代码的可读性和可维护性。

React中获取DOM

在React中,通常我们不建议直接操作DOM,因为React的设计理念是声明式编程,即我们告诉React我们想要什么,而不是如何得到它。React负责高效地更新和渲染DOM。然而,有时候我们可能需要直接访问DOM元素,比如进行手动焦点控制、测量元素尺寸等。

在React中,可以使用React.createRef()useRef() hook来创建refs,然后将它们附加到DOM元素上。这样,我们就可以在组件中通过ref来访问和操作DOM元素。

下面是使用React.createRef()的例子:

import React from 'react';  
  
class MyComponent extends React.Component {  
  constructor(props) {  
    super(props);  
    this.myRef = React.createRef();  
  }  
  
  componentDidMount() {  
    console.log(this.myRef.current); // 访问DOM元素  
  }  
  
  render() {  
    return <div ref={this.myRef}>Hello, World!</div>;  
  }  
}

在函数组件中,你可以使用useRef() hook:

import React, { useRef, useEffect } from 'react';  
  
function MyFunctionComponent() {  
  const myRef = useRef(null);  
  
  useEffect(() => {  
    console.log(myRef.current); // 访问DOM元素  
  }, []);  
  
  return <div ref={myRef}>Hello, World!</div>;  
}

在这两个例子中,myRef是一个ref对象,它被附加到<div>元素上。在类组件中,你可以在componentDidMount生命周期方法中通过this.myRef.current访问DOM元素。在函数组件中,你可以使用useEffect hook来模拟componentDidMount的行为,并同样通过myRef.current来访问DOM元素。

请注意,ref.current会在组件挂载后和卸载前被设置和清除。如果你试图在组件卸载后访问ref.current,它将是null

此外,直接操作DOM应该谨慎使用,并尽量只在React的声明式编程模型无法满足需求时使用。大多数情况下,你应该能够通过状态和props的变化来让React自动处理DOM的更新。