• react组件可以是:class组件函数式组件,然后又细分有状态组件(state)无状态组件,还有其他的类型,不在记录范围内。

  • setState是在class组件中使用的,useStatehooks是在函数式组件中使用的,在react 16.7开始(具体不明)可以使用,但是官方建议react 16.8正式使用;

  • 组件销毁跟vue类似,在父组件可以用一个变量show {show && <Component>},show为false则会销毁(或者不渲染)

setState

setState是异步的,不会立即生效;如果依赖这次操作,可以用另一种写法:setState({prop}, callback)

setState集中处理

函数声明
// change事件
handlerChange = (searchKey, value) => {
    const search = Object.assign({}, this.state.searchData);
    if (searchKey === 'transactionTime') {
        // 交易日期
        search.transactionTimeStart = value.length
            ? moment(value[0]).format('YYYY-MM-DD')
            : '';
        search.transactionTimeEnd = value.length
            ? moment(value[1]).format('YYYY-MM-DD')
            : '';
    }else {
        search[searchKey] = value;
    }
    this.setState({
        searchData: search
    });
};
复制代码
jsx
<Input
  style={{ width: 120 }}
  placeholder="请输入"
  onChange={e => this.handlerChange('coin', e.target.value)}
/>
复制代码

useState

hooks在react函数式组件中使用,

  • useState用来代替class组件中state声明、setState更新数据;
  • useEffect,会在组件初始化、数据更新时被调用,也就是可以用来代替componentDidMount/componentDidUpdate,看到其他掘友的文章说componentWillUnmount时会调用这个函数return 出来的函数,具体实践后就清楚了

useState使用

以下代码可以在codesandbox.io中运行

import ReactDOM from "react-dom";
import React, { useState } from "react";

function NameComp() {
  // 可以传入“initName”作为初始化数据
  const [name, setName] = useState("initName");

  const nameChange = e => setName(e.target.value);

  return (
    <div>
      <p>{name}</p>
      <input onChange={nameChange} />
    </div>
  );
}
const rootElement = document.getElementById("root");
ReactDOM.render(<NameComp />, rootElement);
复制代码

useEffect/useLayoutEffect

useEffect

浏览器完成画面渲染之后才会延迟调用 useEffect,因此会使得额外操作很方便。
可以存在多个,第二个参数可选

  • 有第二个参数(依赖)的话,会根据依赖变化才执行
  • 第二个参数不传的话,每次update都会调用;
  • 第二个参数为空数组的话,相当于 componentDidMount;
  • 如果 return 一个函数,这个函数会在相当于 componentWillUnmount 的时候执行
  const [offsetW, setOffsetW] = useState(0);
  const [offsetH, setOffsetH] = useState(0);
  const [pngUrl, setPngUrl] = useState('');
  const [mdUrl, setMdUrl] = useState('');
  const [exportName, setExportName] = useState('');
  let preview, maxCodeWidth;
  
  useEffect(() => {
    // 显示的内容
    preview = document.querySelector('[class^=md-content]');
    // 获取 code 部分的最大宽度,防止导出图片时,横向滚动条的部分截断
    let codeContent = preview.querySelectorAll('pre>code');
    let codeWidth = Array.from(codeContent).map(codeTag => codeTag.offsetWidth);
    maxCodeWidth = Math.max(...codeWidth);
    setOffsetW(maxCodeWidth);
    setOffsetH(preview.offsetHeight);

    exportfn('png');
    exportfn('md');

    // 回调的函数会在 unmount 时执行
    return () => console.log('Export unmount');

    // 传入第二个参数, 空数组,表示update不执行,[offsetW]表示 offsetW 更新时执行
  }, []);
复制代码
  useEffect(() => {
    console.log('detail mount: ', process.env.NODE_ENV);
    return () => {
      console.log('detail unmount');
    }
  }, []);
复制代码

useLayoutEffect

与useEffect没有太大区别,详看文档

useCallback/useMemo

useCallback

依赖项不变或第二个参数传入空值的话,会执行,但是return的东西不会更新;
类似于 vue 中的 watch,需要先手动调用一次

// pages/detail.js
// ...
  const [count, setCount] = useState(0);
  const [num, setNum] = useState(0);

  // 依赖项 num 不变化的话 会执行,但是不会 return 一个新的 count,即使 count 变化了
  const memorized1 = useCallback(() => {
    console.log(count);
    return count;
  }, [num])();
// ...
复制代码

useMemo

依赖项不变或第二个参数传入空值的话,不执行;
渲染期间根据依赖项执行,不传入依赖的话,每次state更新都会执行,不需要手动调用一次

// pages/detail.js
// ...
  const [count, setCount] = useState(0);
  const [num, setNum] = useState(0);
  
// 依赖项 num 不变化的话 不执行
  const memorized2 = useMemo(() => {
    console.log(count);
    return count;
  }, [num]);
// ...
复制代码

useRef

元素本身:useRef返回值.current

function Comp1() {
  const inputEl = useRef(null);

  function Clk() {
    inputEl.current.focus();
  }
  
  return (
    <>
      <button onClick={Clk}>count+</button>
      <input ref={inputEl} type="text" />
    </>
  );
}
复制代码

useReducer/useContext

具体看这里:React状态管理:redux,rematch,useReducer

useImperativeHandle

以下来自官网文档

useImperativeHandle(ref, createHandle, [deps])
复制代码

useImperativeHandle 可以让你在使用 ref 时自定义暴露给父组件的实例值。在大多数情况下,应当避免使用 ref 这样的命令式代码。useImperativeHandle 应当与 forwardRef 一起使用:

function FancyInput(props, ref) {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
复制代码

在本例中,渲染 的父组件可以调用 fancyInputRef.current.focus()。

useDebugValue

useDebugValue 可用于在 React 开发者工具中显示自定义 hook 的标签。

useDebugValue(value)
复制代码

自定义Hooks

封装一些Hooks的方法,暴露出接口,参考这里

function Comp2() {
  function useNumCalc(num) {
    let [count, setCount] = useState(num);

    return [count, () => setCount(count + 1), () => setCount(count - 1)];
  }

  const [num, numPlus, numMinus] = useNumCalc(1);

  return (
    <>
      num: {num}
      <button onClick={numPlus}>numPlus</button>
      <button onClick={numMinus}>numMinus</button>
    </>
  );
}
复制代码

数据展示

可以用一个字段决定组件是否渲染,如show && <Component />,show为true时渲染; 注意如果show是数组,应该用show.length > 1作为条件,而不是show.length && <Component />

表格列自定义内容render: (antd)

...
<LocaleProvider locale={zh_CN}>
  <Table
    bordered
    loading={this.state.tableLoading}
    dataSource={this.state.tableData}
    pagination={this.getPaginationProps()}
  >
    {Object.keys(columnText).map(key =>
      key === 'operation' ? ( // 操作列
        <Column
          title={columnText[key]}
          align="center"
          dataIndex={key}
          key={key}
          render={(text, row) => (
            <div>
              <span className={styles.a} onClick={() => this.edit(row)}>
                修改
              </span>
              &emsp;
              <span
                className={styles.a}
                onClick={() => this.delete(row)}
              >
                删除
              </span>
            </div>
          )}
        />
      ) : (
        // 其他列
        <Column
          title={columnText[key]}
          align="center"
          dataIndex={key}
          key={key}
        />
      )
    )}
  </Table>
</LocaleProvider>
...
复制代码

表格列抽出遍历:(antd)

// 省略其他代码
...
  render() {
    const { Column } = Table;
    // 表格列 对应的 key和名称
    const columnText = {
      No: '序号',
      coinName: '币种',
      maxAmountPerOrder: '单笔限额',
      maxAmountPerDay: '日累计限额',
      latestUpdatedTime: '最后编辑时间',
      latestEditor: '最后编辑人',
      operation: '操作'
    };

    return (
      <div className={styles.withdrawalConfig}>
        <LocaleProvider locale={zh_CN}>
          <Table
            bordered
            scroll={{ y: this.state.tableHeight }}
            dataSource={tableData}
            pagination={this.getPaginationProps()}
          >
            {Object.keys(columnText).map(key =>
              key === 'operation' ? ( // 操作列
                <Column
                  title={columnText[key]}
                  align="center"
                  dataIndex={key}
                  key={key}
                  width="12%"
                  render={(text, row) => (
                    <div>
                      <span className={styles.a} onClick={() => this.edit(row)}>
                        修改
                      </span>
                      &emsp;
                      <span
                        className={styles.a}
                        onClick={() => this.delete(row)}
                      >
                        删除
                      </span>
                    </div>
                  )}
                />
              ) : (
                // 其他列
                <Column
                  title={columnText[key]}
                  align="center"
                  dataIndex={key}
                  key={key}
                  width={key === 'No' ? '6%' : '12%'}
                />
              )
            )}
          </Table>
        </LocaleProvider>
      </div>
    );
  }
  ...
复制代码

转载于:https://juejin.im/post/5cc2d409f265da03650501f3

Logo

前往低代码交流专区

更多推荐