• react 笔记


    react 笔记

    React 用于构建用户界面的 js库。使用 React 可以将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作“组件”。
    class组件
    通过 class 定义组件,继承React.Component,定义render方法使用jsx语法书写结构,返回一个React元素。
    访问属性: this.props
    添加点击事件:onClick={fn}
    定义状态:在constructor 初始化 this.state
    修改状态:this.setState,只会指定属性的值。
    多组件共享状态:在父组件中定义状态,然后通过props传递给子组件。click函数同样。
    不可变性:不直接修改数据有利于追踪数据变化,实现回退功能。确定组件渲染时间。

    class ShoppingList extends React.Component {
      constructor(props) {
       super(props);
        this.state = {
          value: null,
        };
      }
    
      render() {
        return (
          <div className="shopping-list">
            <h1>Shopping List for {this.props.name}</h1>
            <button
              className="square"
              onClick={() => this.setState({value: 'X'})}>
    	        {this.state.value}
    	    </button>
            <ul>
              <li>Instagram</li>
              <li>WhatsApp</li>
              <li>Oculus</li>
            </ul>
          </div>
        );
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    函数组件
    接受props属性,返回一个React元素
    访问属性: props

    function Square(props) {
      return (
        <button className="square" onClick={props.onClick}>
          {props.value}
        </button>
      );
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    key的作用
    列表渲染时,判断如果现在存在,但之前不存在这个key会创建这个元素;如果现在不存在,但之前存在会删除这个元素。如果key发生了变化。会删除之前的然后新创建一个。
    数组的索引不适合作为key。排序、新增、删除操作时,数组的索引会变动。导致key变动,导致渲染问题。

    JSX语法

    1. 将变量用大括号包裹。
    const element = <h1>Hello, {name}</h1>;
    2. 执行函数表达式
    function formatName(user) {
      return user.firstName + ' ' + user.lastName;
    }
    const element = <h1>Hello, {formatName(user)}</h1>;
    3. 访问属性
    const element = <img src={user.avatarUrl}></img>;
    4. 添加属性名,采用驼峰命名
    const element = <h1 className="hell">Hello</h1>;
    
    5. 闭合标签 />
    const element = <img src={user.avatarUrl} />;
    
    6. 防止XSS注入攻击,title在被渲染之前会被自动转义。
    const title = response.potentiallyMaliciousInput;
    const element = <h1>{title}</h1>;
    
    8. 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    元素渲染

    
    1. 这种我们称之为元素,是一个普通对象。是不可变的。跟浏览器的元素不一样。需要执行ReactDOM.render渲染
    const element = <h1>Hello, world</h1>;
    ReactDOM.render(element, document.getElementById('root'));
    2. 元素和组件不一样。
    3. 自定义组件也可以做元素。属性会被转为对象传递给组件。
    const element = <Welcome name="Sara" />;
    4. 元素渲染流程
    首先通过ReacDOM.render渲染元素element 。然后调用Welcome组件,传入属性。Welcome组件返回render内容。React DOM更新内容。
    5. 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    组件

    
    1. 组件名必须大写。
    2. 提取组件。
    function Avatar(props) {
      return (
        <img className="Avatar"
          src={props.user.avatarUrl}
          alt={props.user.name}
        />
      );
    }
    3. 组合组件。
    function App() {
      return (
        <div>
          <Welcome name="Sara" />
          <Welcome name="Cahal" />
          <Welcome name="Edite" />
        </div>
      );
    }
    4. props只读。
    不能修改自身的 props
    5. 通过State让组件自我更新。
    在class组件的constructor中初始化state。在render中调用。在componentDidMount中添加定时器修改。在componentWillUnmount中删除定时器。
    调用顺序:首先React 调用 Clock组件的构造函数。初始化state。调用组件的render。更新DOM。执行生命周期函数ComponentDidMount,设置计时器。浏览器执行定时器。调用setState。React得知state变化。重新调用render。一旦Clock组件移除。执行生命周期函数componentWillUnmount。
    class Clock extends React.Component {
      constructor(props) {
        super(props);
        this.state = {date: new Date()};
      }
      
      componentDidMount() {
        this.timerID = setInterval(
          () => this.tick(),
          1000
        );
      }
    
      componentWillUnmount() {
        clearInterval(this.timerID);
      }
    
      tick() {
        this.setState({
          date: new Date()
        });
      }
      render() {
        return (
          <div>
            <h1>Hello, world!</h1>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
          </div>
        );
      }
    }
    6. state
    不可直接修改。只能通过setState调用。
    State 的更新可能是异步的。
    setState不能依赖state修改
    this.setState({
      counter: this.state.counter + this.props.increment,
    });
    可以通过函数
    // Correct
    this.setState((state, props) => ({
      counter: state.counter + props.increment
    }));
    State 的更新会被合并,合并是浅合并,不会修改其他state
    this.setState({
      posts: response.posts
    });
    this.setState({
     comments: response.comments
    });
    7. 数据自上向下流动。
    8. 事件处理
    驼峰命名
    <button onClick={activateLasers}>Activate Lasers</button>
    不能通过返回 false 的方式阻止默认行为
    在class组件中使用,需要在constructor中绑定this或者使用箭头函数。onClick={() => this.handleClick()}
    class Toggle extends React.Component {
      constructor(props) {
        super(props);
        this.state = {isToggleOn: true};
    
        // 为了在回调中使用 `this`,这个绑定是必不可少的
        this.handleClick = this.handleClick.bind(this);
      }
    
      handleClick() {
        this.setState(state => ({
          isToggleOn: !state.isToggleOn
        }));
      }
    
      render() {
        return (
          <button onClick={this.handleClick}>
            {this.state.isToggleOn ? 'ON' : 'OFF'}
          </button>
        );
      }
    }
    
    ReactDOM.render(
      <Toggle />,
      document.getElementById('root')
    );
    传递参数
    <button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
    9. 条件渲染。
    通过if
    function Greeting(props) {
      const isLoggedIn = props.isLoggedIn;
      if (isLoggedIn) {
        return <UserGreeting />;
      }
      return <GuestGreeting />;
    }
    通过与运算符 &&
    isLoggedIn 为true才会渲染。为false会被忽略。
    function Greeting(props) {
      const isLoggedIn = props.isLoggedIn;
      return isLoggedIn && <UserGreeting />;
    }
    三目运算符
    render() {
      const isLoggedIn = this.state.isLoggedIn;
      return (
        <div>
          The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
        </div>
      );
    }
    阻止条件渲染
    render 方法直接返回 null
    10. 列表渲染
    function NumberList(props) {
      const numbers = props.numbers;
      const listItems = numbers.map((number) =>
        <li key={number.toString()}>
          {number}
        </li>
      );
      return (
        <ul>{listItems}</ul>
      );
    }
    
    const numbers = [1, 2, 3, 4, 5];
    ReactDOM.render(
      <NumberList numbers={numbers} />,
      document.getElementById('root')
    );
    内联map
    function NumberList(props) {
      const numbers = props.numbers;
      return (
        <ul>
          {numbers.map((number) =>
            <ListItem key={number.toString()}
                      value={number} />
          )}
        </ul>
      );
    }
    11. 表单
    受控组件:state作为数据源。通过setState更新。
    同类标签input、textarea、select
    <input type="text" value={this.state.value} onChange={this.handleChange} />
    handleChange(event) {
     this.setState({value: event.target.value});
    }
    非受控组件
    真实数据储存在 DOM 节点
    <input type="text" ref={this.input} />
    alert('A name was submitted: ' + this.input.current.value);
    Formik
    import React from 'react';
    import {useFormik } from 'formik';
    
    const SignupForm = () => {
      // Note that we have to initialize ALL of fields with values. These
      // could come from props, but since we don’t want to prefill this form,
      // we just use an empty string. If we don’t do this, React will yell
      // at us.
      const formik = useFormik({
        initialValues: {
          firstName: '',
          lastName: '',
          email: '',
        },
        onSubmit: values => {
          alert(JSON.stringify(values, null, 2));
        },
      });
      return (
        <form onSubmit={formik.handleSubmit}>
          <label htmlFor="firstName">First Name</label>
          <input
            id="firstName"
            name="firstName"
            type="text"
            onChange={formik.handleChange}
            value={formik.values.firstName}
          />
    
          <label htmlFor="lastName">Last Name</label>
          <input
            id="lastName"
            name="lastName"
            type="text"
            onChange={formik.handleChange}
            value={formik.values.lastName}
          />
    
          <label htmlFor="email">Email Address</label>
          <input
            id="email"
            name="email"
            type="email"
            onChange={formik.handleChange}
            value={formik.values.email}
          />
    
          <button type="submit">Submit</button>
        </form>
      );
    };
    12. 组合与继承
    使用children,子节点内容由父节点确定
    function FancyBorder(props) {
      return (
        <div className={'FancyBorder FancyBorder-' + props.color}>
          {props.children}
        </div>
      );
    }
    通过属性left、right传递不同的组件。
    function SplitPane(props) {
      return (
        <div className="SplitPane">
          <div className="SplitPane-left">
            {props.left}
          </div>
          <div className="SplitPane-right">
            {props.right}
          </div>
        </div>
      );
    }
    
    function App() {
      return (
        <SplitPane
          left={
            <Contacts />
          }
          right={
            <Chat />
          } />
      );
    }
    如果你想要在组件间复用非 UI 的功能,我们建议将其提取为一个单独的 JavaScript 模块,如函数、对象或者类。组件可以直接引入(import)而无需通过 extend 继承它们。
    13. React开发步骤
    首先根据设计UI划分组件层级(根据单一功能原则把组件当做一个函数或对象,如果它负责更多的功能,应该拆分成更小的组件);
    然后用React 创建一个静态版本(自上而下比较方便,但自下而上适合大型项目同时编写测试更简单)
    然后确定需要用到的最小且完整的state
    然后确定state位置(所有需要用到该state的共同父级,如果没有就创建一个)。
    最后添加反向数据流(较低层组件通过事件更新较高层级组件的state)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272

    高级功能

    
    1. 代码分割
    避免代码体积过大导致加载时间过长;避免加载用户不需要的代码。
    动态 import()
    import { add } from './math';
    console.log(add(16, 26));
    例如
    import("./math").then(math => {
      console.log(math.add(16, 26));
    });
    React.lazy
    import OtherComponent from './OtherComponent';
    例如
    const OtherComponent = React.lazy(() => import('./OtherComponent'));
    然后应在 Suspense 组件中渲染 lazy 组件
    import React, { Suspense } from 'react';
    
    const OtherComponent = React.lazy(() => import('./OtherComponent'));
    
    function MyComponent() {
      return (
        <div>
          <Suspense fallback={<div>Loading...</div>}>
            <OtherComponent />
          </Suspense>
        </div>
      );
    }
    基于路由的代码分割
    import React, { Suspense, lazy } from 'react';
    import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
    
    const Home = lazy(() => import('./routes/Home'));
    const About = lazy(() => import('./routes/About'));
    
    const App = () => (
      <Router>
        <Suspense fallback={<div>Loading...</div>}>
          <Switch>
            <Route exact path="/" component={Home}/>
            <Route path="/about" component={About}/>
          </Switch>
        </Suspense>
      </Router>
    );
    React.lazy 目前只支持默认导出(default exports)
    
    2. Context
    Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法
    适合管理locale,theme,或者一些缓存数据	
    通过React.createContext创建context对象
    通过ThemeContext.Provider并设置value向下传递context内容
    多个 Provider 也可以嵌套使用,里层的会覆盖外层的数据。
    当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染。
    ** 设置MyClass.contextType = MyContext; class组件可以直接通过 this.context消费context
    ** 设置MyContext.Consumer消费
    <MyContext.Consumer>
      {value => /* 基于 context 值进行渲染*/}
    </MyContext.Consumer>
    
    不利于组件的复用(替代方案使用组件组合,将底层组件整个传递下去,但会使组件更复杂)
    const ThemeContext = React.createContext('light');
    class App extends React.Component {
      render() {
        // 使用一个 Provider 来将当前的 theme 传递给以下的组件树。
        // 无论多深,任何组件都能读取这个值。
        // 在这个例子中,我们将 “dark” 作为当前的值传递下去。
        return (
          <ThemeContext.Provider value="dark">
            <Toolbar />
          </ThemeContext.Provider>
        );
      }
    }
    动态 Context
    将context内容设置为一个对象。
    theme-context.js
    export const themes = {
      light: {
        foreground: '#000000',
        background: '#eeeeee',
      },
      dark: {
        foreground: '#ffffff',
        background: '#222222',
      },
    };
    
    export const ThemeContext = React.createContext(
      themes.dark // 默认值
    );
    themed-button.js
    import {ThemeContext} from './theme-context';
    
    class ThemedButton extends React.Component {
      render() {
        let props = this.props;
        let theme = this.context;
        return (
          <button
            {...props}
            style={{backgroundColor: theme.background}}
          />
        );
      }
    }
    ThemedButton.contextType = ThemeContext;
    
    export default ThemedButton;
    
    app.js
    import {ThemeContext, themes} from './theme-context';
    import ThemeTogglerButton from './theme-toggler-button';
    
    class App extends React.Component {
      constructor(props) {
        super(props);
    
        this.toggleTheme = () => {
          this.setState(state => ({
            theme:
              state.theme === themes.dark
                ? themes.light
                : themes.dark,
          }));
        };
    
        // State 也包含了更新函数,因此它会被传递进 context provider。
        this.state = {
          theme: themes.light,
          toggleTheme: this.toggleTheme,
        };
      }
    
      render() {
        // 整个 state 都被传递进 provider
        return (
          <ThemeContext.Provider value={this.state}>
            <Content />
          </ThemeContext.Provider>
        );
      }
    }
    
    function Content() {
      return (
        <div>
          <ThemeTogglerButton />
        </div>
      );
    }
    
    ReactDOM.render(<App />, document.root);
    消费多个 Context
    // 一个组件可能会消费多个 context
    function Content() {
      return (
        <ThemeContext.Consumer>
          {theme => (
            <UserContext.Consumer>
              {user => (
                <ProfilePage user={user} theme={theme} />
              )}
            </UserContext.Consumer>
          )}
        </ThemeContext.Consumer>
      );
    }
    3. 错误边界
    错误边界是一个React 组件,捕获子组件树上的js错误,并渲染备用UI
    实现方式,在class组件上定义 static getDerivedStateFromError或componentDidCatch方法
    class ErrorBoundary extends React.Component {
      constructor(props) {
        super(props);
        this.state = { hasError: false };
      }
    
      static getDerivedStateFromError(error) {
        // 更新 state 使下一次渲染能够显示降级后的 UI
        return { hasError: true };
      }
    
      componentDidCatch(error, errorInfo) {
        // 你同样可以将错误日志上报给服务器
        logErrorToMyService(error, errorInfo);
      }
    
      render() {
        if (this.state.hasError) {
          // 你可以自定义降级后的 UI 并渲染
          return <h1>Something went wrong.</h1>;
        }
    
        return this.props.children; 
      }
    }
    <ErrorBoundary>
      <MyWidget />
    </ErrorBoundary>
    4. Refs 转发
    将ref通过组件传递到子组件,主要解决类似FancyButton 这样封装单个控件的高可复用组件可以直接对button进行操作。一般不推荐使用。
    React.createRef()创建ref;React.forwardRef接收ref
    const FancyButton = React.forwardRef((props, ref) => (
      <button ref={ref} className="FancyButton">
        {props.children}
      </button>
    ));
    
    // 你可以直接获取 DOM button 的 ref:
    const ref = React.createRef();
    <FancyButton ref={ref}>Click me!</FancyButton>;
    
    5. Fragments
    一个组件返回多个元素
    无需向 DOM 添加额外节点
    render() {
      return (
        <React.Fragment>
          <ChildA />
          <ChildB />
          <ChildC />
        </React.Fragment>
      );
    }
    短语法
    class Columns extends React.Component {
      render() {
        return (
          <>
            <td>Hello</td>
            <td>World</td>
          </>
        );
      }
    }
    6. 高阶组件
    高阶组件是参数为组件,返回值为新组件的函数
    组件是将 props 转换为 UI,而高阶组件是将组件转换为另一个组件
    使用 HOC 解决横切关注点问题
    不要改变原始组件。
    不要将不相关的 props 传递给被包裹的组件
    包装显示名称以便轻松调试
    不要在 render 方法中使用 HOC,这将导致子树每次渲染都会进行卸载,和重新挂载的操作!
    // 此函数接收一个组件...
    function withSubscription(WrappedComponent, selectData) {
      // ...并返回另一个组件...
      return class extends React.Component {
        constructor(props) {
          super(props);
          this.handleChange = this.handleChange.bind(this);
          this.state = {
            data: selectData(DataSource, props)
          };
        }
    
        componentDidMount() {
          // ...负责订阅相关的操作...
          DataSource.addChangeListener(this.handleChange);
        }
    
        componentWillUnmount() {
          DataSource.removeChangeListener(this.handleChange);
        }
    
        handleChange() {
          this.setState({
            data: selectData(DataSource, this.props)
          });
        }
    
        render() {
          // ... 并使用新数据渲染被包装的组件!
          // 请注意,我们可能还会传递其他属性
          return <WrappedComponent data={this.state.data} {...this.props} />;
        }
      };
    }
    
    const CommentListWithSubscription = withSubscription(
      CommentList,
      (DataSource) => DataSource.getComments()
    );
    
    7. 深入JSX
    在运行时选择组件类型
    import React from 'react';
    import { PhotoStory, VideoStory } from './stories';
    
    const components = {
      photo: PhotoStory,
      video: VideoStory
    };
    
    function Story(props) {
      // 正确!JSX 类型可以是大写字母开头的变量。
      const SpecificStory = components[props.storyType];
      return <SpecificStory story={props.story} />;
    }
    属性展开
    function App2() {
      const props = {firstName: 'Ben', lastName: 'Hector'};
      return <Greeting {...props} />;
    }
    函数作为子元素
    function ListOfTenThings() {
      return (
        <Repeat numTimes={10}>
          {(index) => <div key={index}>This is item {index} in the list</div>}
        </Repeat>
      );
    }
    布尔类型、Null 以及 Undefined 将会忽略
    
    8. Render
    使用 Render Props 来解决横切关注点
    这个组件的问题无法复用;state要复用的话一定要提取出来。
    class MouseTracker extends React.Component {
      constructor(props) {
        super(props);
        this.handleMouseMove = this.handleMouseMove.bind(this);
        this.state = { x: 0, y: 0 };
      }
    
      handleMouseMove(event) {
        this.setState({
          x: event.clientX,
          y: event.clientY
        });
      }
    
      render() {
        return (
          <div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
            <h1>移动鼠标!</h1>
            <p>当前的鼠标位置是 ({this.state.x}, {this.state.y})</p>
          </div>
        );
      }
    }
    解决方案
    Mouse组件提供坐标;Cat组件可以被轻松替换成其他组件。Mouse和Cat都有使用相同的state,是由Mouse传递出来的。Cat在Mouse内被渲染,但是却在Mouse外确定。因此Cat组件很灵活。
    这里的render名字只是名字,也可以是children等之类的名称
    class Cat extends React.Component {
      render() {
        const mouse = this.props.mouse;
        return (
          <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
        );
      }
    }
    
    class Mouse extends React.Component {
      constructor(props) {
        super(props);
        this.handleMouseMove = this.handleMouseMove.bind(this);
        this.state = { x: 0, y: 0 };
      }
    
      handleMouseMove(event) {
        this.setState({
          x: event.clientX,
          y: event.clientY
        });
      }
    
      render() {
        return (
          <div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}>
    
            {/*
              Instead of providing a static representation of what  renders,
              use the `render` prop to dynamically determine what to render.
            */}
            {this.props.render(this.state)}
          </div>
        );
      }
    }
    
    class MouseTracker extends React.Component {
      render() {
        return (
          <div>
            <h1>移动鼠标!</h1>
            <Mouse render={mouse => (
              <Cat mouse={mouse} />
            )}/>
          </div>
        );
      }
    }
    
    9. StrictMode 
    识别不安全的生命周期
    关于使用过时字符串 ref API 的警告
    关于使用废弃的 findDOMNode 方法的警告
    检测意外的副作用
    检测过时的 context API
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398

    HOOK
    不编写 class 的情况下使用 state
    解决在组件之间复用状态逻辑很难,Hook 将组件中相互关联的部分拆分成更小的函数
    解决难以理解的 class
    只能在函数最外层调用 Hook
    只能在 React 的函数组件中调用 Hook
    Hook 是特殊的函数,让你可以“钩入”React的特性。

    
    1. State Hook
    在函数组件中调用 useState,参数是设置state的初始值,返回当前 state 以及更新 state 的函数
    state可以是多个也可以对象等类型
    import React, { useState } from 'react';
    
    function Example() {
      // 声明一个叫 “count” 的 state 变量。
      const [count, setCount] = useState(0);
      const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
    
      return (
        <div>
          <p>You clicked {count} times</p>
          <button onClick={() => setCount(count + 1)}>
            Click me
          </button>
        </div>
      );
    }
    2. Effect Hook
    在函数组件中调用 useEffect , 组件更新时自动执行。可以通过返回一个函数清除该副作用。
    function FriendStatusWithCounter(props) {
      const [count, setCount] = useState(0);
      useEffect(() => {
        document.title = `You clicked ${count} times`;
      });
    
      const [isOnline, setIsOnline] = useState(null);
      useEffect(() => {
        ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
        return () => {
          ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
        };
      });
    3. 自定义 Hook
    通过useState 和 useEffect
    复用逻辑而不是状态
    import React, { useState, useEffect } from 'react';
    
    function useFriendStatus(friendID) {
      const [isOnline, setIsOnline] = useState(null);
    
      function handleStatusChange(status) {
        setIsOnline(status.isOnline);
      }
    
      useEffect(() => {
        ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
        return () => {
          ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
        };
      });
    
      return isOnline;
    }
    
    4. useContext
    const locale = useContext(LocaleContext); 不嵌套组件就可以实现context的订阅
    const theme = useContext(ThemeContext);
    
    const [todos, dispatch] = useReducer(todosReducer);通过 reducer 来管理组件本地的复杂 state。
    
    5. 比较class组件
    class组件中 的副作用放在 componentDidMount 或者 componentDidUpdate 中。
    useEffect 直接执行副作用,可以在useEffect 里面执行dom 访问。数据获取。可以直接访问 state、props
    componentDidMount() {
     document.title = `You clicked ${this.state.count} times`;
    }
    componentDidUpdate() {
     document.title = `You clicked ${this.state.count} times`;
    }
    useEffect(() => {
     document.title = `You clicked ${count} times`;
    });
    副作用清除。class组件是在componentWillUnmount中。
    useEffect 直接返回清除副作用的函数。
    class组件在处理订阅时还需要在组件更新时执行清除然后订阅的操作;useEffect每次更新都会自动清除然后添加订阅。
    性能优化:useEffect传入第二个参数,只有当参数数组里面的某个state变化才执行副作用。
    useEffect(() => {
      document.title = `You clicked ${count} times`;
    }, [count]); // 仅在 count 更改时更新
    如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])作为第二个参数。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
  • 相关阅读:
    Python神经网络入门与实战,神经网络算法python实现
    开发一个npm组件包(2)
    东华大学 2022 oj c++ 无超纲写法 素数表
    css实现三角形
    前端研习录(21)——JavaScript循环语句合集
    招聘程序员(软件开发工程师),如何做岗位胜任力测评?
    使用百度云服务器申请ssl证书配置报错问题
    java毕业设计开题报告SSM图书馆预约占座系统
    网页大作业代码自取【HTML+CSS制作美味糖果网站】
    mongodb 在windows下 安装及使用
  • 原文地址:https://blog.csdn.net/qq_38862234/article/details/127868551