react学习笔记

react学习笔记

react的入门学习笔记(就是照抄官方文档)

学习路径

核心概念

起步实践

  1. 用Nx建立第一个react项目

  2. 封装CSS3-based的烟花组件 (学习写css样式的方法、JSX、组件传参Props)

    React中使用CSS样式的三种方法

    1. 行内/声明样式:样式作为js对象传入组件的style属性

    2. import样式

      使用*.module.css防止样式全局污染,使用className={moduleName.className}以引用

    3. styled components:从组件的层面对 CSS 进行封装

其他核心概念

state

  • 函数组件转换成class组件

    1. 创建一个同名的 ES6 class,并且继承于 React.Component
    2. 添加一个空的 render() 方法。
    3. 将函数体移动到 render() 方法之中。
    4. render() 方法中使用 this.props 替换 props
    5. 删除剩余的空函数声明。
  • 向class组件添加局部的state

    1. 添加一个class构造函数,在函数中为this.state赋初值。同时将props传递到父类的构造函数

      1
      2
      3
      4
      constructor(props) {
      super(props);
      this.state = {date: new Date()};
      }
    2. 使用this.state.name调用,使用this.setState()对整个state对象进行更新

      • 不要直接修改State,请使用this.setState方法。构造函数是唯一可以给this.state赋值的地方

      • 因为this.propsthis.state可能会异步更新,不要依赖他们的值来更新下一个状态,可以通过使this.setState()接受一个函数来解决异步的问题

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        // Wrong
        this.setState({
        counter: this.state.counter + this.props.increment,
        });
        // Correct
        this.setState((state, props) => ({
        counter: state.counter + props.increment
        }));
        // Correct
        this.setState(function(state, props) {
        return {
        counter: state.counter + props.increment
        };
        })

事件处理

  • 回调函数必须进行绑定

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     // 方案一 构造器绑定
    constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
    }
    // 方案二 public class fields 语法
    handleClick = () => {
    console.log('this is:', this);
    }
    // 方案三 调用时使用箭头函数(当回调函数作为prop传入子组件时此方案会产生性能问题)
    render() {
    return (
    <button onClick={() => this.handleClick()}>
    Click me
    </button>

    );
    }
  • 向事件处理函数传递参数

    1
    2
    <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
    <button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
  • 子组件向父组件通信:在父组件向子组件将某个事件处理函数作为props传入,子组件调用

条件渲染

  • 使用变量存储元素
  • 与运算符&&
    • true && expression 总是会返回 expression
    • false && expression 总是会返回 false
  • 三目运算符

列表和key

  • 不需要改变列表项目顺序时,才能使用index作为列表key:列表中的key有什么用:知乎
  • 元素的key只有放在就近的数组上下文中才有意义:map()中的元素需要设置key属性
  • key值仅仅对React有效,若程序需要获取该值则需要使用其他的属性名传入

表单

  • 表单元素(如<input><textarea><select>)之类的表单元素自己维护 state,并根据用户输入进行更新,它们原本是非受控组件。在React可以通过使它们接受value属性,编写onChange()事件方法使它们成为受控组件(受控组件:输入的值由React的state驱动)

    受控组件

    • 文件input标签
    1
    <input type="file" />
    • 处理多个输入:给每个元素添加 name 属性,并让处理函数根据 event.target.name 的值选择要执行的操作
    • 受控组件上value属性值接受到undefinednull时会重新成为非受控组件,并且终端会提示

状态提升

  • 通过状态提升的例子理解以上React中的核心概念,实现父子组件传值、兄弟组件通讯

使用组合代替继承

  • 包含关系

    • 特殊的children prop:组件标签中的所有内容都会作为childrenprop

    • 使用props传入组件并在展示在预留的位置:类似slot的概念,但是React任何东西都是作为props传递

  • 特例关系:“特殊”组件可以通过 props 定制并渲染“一般”组件:

理解hook

React ^16.8允许在不编写class的情况下使用state等react属性,Hook开发的动机:

  • 组件间共享状态逻辑

    在组件之间重用一些状态逻辑。目前为止,有两种主流方案来解决这个问题:高阶组件render props。自定义 Hook 可以让你在不增加组件的情况下达到同样的目的。

  • 拆分复杂组件内相互关联的部分

  • 函数组件替代Class组件

hook的使用规则:

  • 只能在函数最外层调用
  • 只能在函数组件调用

内置HooK

useState

操作组件state:调用useState()添加state。useState()返回当前状态(this.state.name)和一个更新该状态的函数(this.setState()),参数为state的初始值

1
2
3
function ExampleComponent(){
const [something,setSomething] = useState(100)
}

在state hook中更新一个 state 变量,会 替换 它的值。这和 class 中的 this.setState不一样,后者会把更新后的字段 合并 入对象中。因此,建议降低组件中state对象的拆分粒度

useEffect
  • 操作组件的生命周期:它跟 class 组件中的 componentDidMountcomponentDidUpdatecomponentWillUnmount 具有相同的用途,只不过被合并成了一个 API。useEffect在执行DOM更新后被调用

    1
    2
    3
    4
    5
    6
    7
    8
    useEffect(() => {
    // 相当于 componentDidMount 和 componentDidUpdate:
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
    // 相当于 componentWillUnmount:
    ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
    });

    大多数情况下,Effect 不需要同步地执行。在个别情况下(例如测量布局),有单独的 useLayoutEffect Hook 供你使用,其 API 与 useEffect 相同。

  • 清除effect:在Effect返回一个清除函数,React会在组件卸载的时候执行清除操作。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    useEffect(() => {
    function handleStatusChange(status) {
    setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
    ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
    });
  • 跳过Effect进行性能优化:如果某些特定值在两次重渲染之间没有发生变化,你可以通知 React 跳过对 effect 的调用,只要传递数组作为 useEffect 的第二个可选参数即可:

    1
    2
    3
    useEffect(() => {
    document.title = `You clicked ${count} times`;
    }, [count]); // 仅在 count 更改时更新

提示:

  • Hook的目的:实现关注点分离(单个操作逻辑完整性)。按照代码的用途分离多个effect
  • 每次更新都会运行hook,除非指定跳过

Hook规则

  • 只在最顶层使用,不再循环、条件或嵌套函数中调用Hook。因为React依赖Hook调用顺序确定state对应的useState,Hook 的调用顺序在每次渲染中相同才能保证正确性。
  • 只在React函数中调用Hook
    • 在React函数组件中调用Hook
    • 在自定义Hook中调用其他Hook

自定义hook

  • 自定义 Hook 更像是一种约定而不是功能。如果函数的名字以 “use” 开头并调用其他 Hook,我们就说这是一个自定义 Hook。 useSomething 的命名约定可以让我们的 linter 插件在使用 Hook 的代码中找到 bug。

提示

  • 在多个Hook之间传递信息:
useContext

订阅React的Context

useReducer

通过reducer管理组件本地的复杂state,useState 的替代方案。它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法。(如果你熟悉 Redux 的话,就已经知道它如何工作了。)

1
const [state, dispatch] = useReducer(reducer, initialArg, init);

tips:

  • 用户定义的组件名必须以大写字母开头(大驼峰):深入 JSX
  • 事件命名采用小驼峰式

title:react学习笔记

author:Anne416wu

link:https://www.annewqx.top/posts/34831/

publish time:2022-01-18

update time:2022-09-16


 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×