IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> react实现父组件直接执行子组件的方法(useRef) -> 正文阅读

[JavaScript知识库]react实现父组件直接执行子组件的方法(useRef)

今天遇到这样一个需求:

一个很简单的左右布局。要实现点击左侧数据更新右侧表格。这个表格因为在多处用到,所以被单独封装。表格勾选和全选的逻辑写在了表格这个组件内部。而这也导致了一个问题:每次点击左侧的数据,右侧的表格并没有重置状态。那如何解决这个问题?

表格的全选和勾选与全选的状态关联是根据selectRowKeys来控制的。如果selectRowKeys=[],那表格每行的勾选状态将被清空。所以关键就是要在每次点击左侧树形菜单的时候进selectRowKeys的操作。

第一种方法:既然表格的状态被单独封装到了表格的组件里。那我再点击父组件左侧的树形菜单时,直接操作表格组件本身,然后通过组件本身的方法去做操作不就可以了吗?沿着这个思路。

我们引出来reactHooks里几个钩子:

useImperativeHandle

useRef

forwardRef

具体使用如下:

(1)父组件使用?useRef?创建一个?ref?传入 子组件

const childrenRef = useRef(null);

return <children ref={childrenRef} />

(2)子组件使用?useImperativeHandle?暴露?ref?自定义的实例值给父组件。这个需要用?forwardRef?包裹

function children(props, ref) {
    useImperativeHandle(ref, () => ({
        hello: () => console.log('hello world!')
    }))
    return <h1>children</h1>
}
export default forwardRef(children);

最后在父组件中调用

const childrenRef = useRef(null);
const something = () => childrenRef.current.hello();

还是回到我们的表格这个案例。我们看看封装的table这个组件



import { useState, useEffect, useImperativeHandle, forwardRef } from "react"
import {
  Table,
  Row,
  Col,
  Checkbox
} from "antd"
import "./index.less"

function QuotaTable(props, ref) {
  console.log("表格props:", props)
  let { columns,
    dataSource,
    total,
    resetTable,
    queryQuotaByPage,
    renderTitleRtConts = <span></span>
  } = props
  // renderTitleRtConts 头部右侧操作内容
  const [selectedRowKeys, setSelectedRowKeys] = useState([])
  const [isCheckeAll, setIsCheckeAll] = useState(false)


  const reset = () => {
    setSelectedRowKeys([])
    setIsCheckeAll(false)
  }

  const selectAll = (e) => {
    let keys = []
    if (e.target.checked) {
      keys = dataSource.map(i => i.key)
    } else {
      keys = []
    }
    console.log("keys:", keys)
    setSelectedRowKeys(keys)
    setIsCheckeAll(e.target.checked)
    props.getSelectedTableIds(keys)
  }
  const changePage = (cur) => {
    console.log("cur:", cur)
    queryQuotaByPage(cur)
  }

  const rowSelection = {
    onChange: (selectedRowKeys, selectedRows) => {
      if (selectedRowKeys.length === dataSource.length) {
        setSelectedRowKeys(selectedRowKeys)
        setIsCheckeAll(true)
      } else {
        setSelectedRowKeys(selectedRowKeys)
        setIsCheckeAll(false)
      }
      props.getSelectedTableIds(selectedRowKeys)
    },
    selectedRowKeys,
    getCheckboxProps: (record) => ({
      disabled: record.name === 'Disabled User',
      name: record.name,
    }),
  };

  useImperativeHandle(ref,
    () => ({
      selectAll,
      reset,
      rowSelection
    }))
  //分液器设置
  const paginationProps = {
    showSizeChanger: true,//设置每页显示数据条数
    showQuickJumper: false,
    showTotal: () => `共${total}条`,
    pageSize: 20,
    total,  //数据的总的条数
    onChange: (current) => changePage(current), //点击当前页码
  }


  return (
    <div className="quota-container">
      <Table
        size="small"
        loading={props.loading}
        title={(data) =>
          <div className="table-title">
            <Row>
              <Col span={12}>
                <Checkbox
                  onChange={(e) => selectAll(e)}
                  checked={isCheckeAll}>全选</Checkbox>
                  已选<span className="num">{selectedRowKeys.length}</span>个对象,共1200个对象
              </Col>
              <Col span={12} >
                <div className="table-title-rt">{renderTitleRtConts}</div>
              </Col>
            </Row>
          </div>
        }
        resetTable={resetTable}
        hideSelectAll={true}
        rowSelection={rowSelection}
        columns={columns}
        dataSource={dataSource}
        pagination={paginationProps}
      >
      </Table>
    </div>
  )
}
export default forwardRef(QuotaTable)

注意:我们把要暴露出去的方法通过useImperativeHandle进行包装,通过把QuotaTable这个组件通过forwardRef进行包裹。这里我们其实只需要暴露reset这个方法即可。

最后我们在父组件中调用:

const selectTree = (selectedKeys, { node }) => {

    let item = deepCopy(node)
    let params = {}
    if (node.code) { //点击其他层级
      params = { ...quotaParams, categoryId: node.id, shopCode: activeKey, setMealCode: node.code }
    } else {
      params = { ...quotaParams, setMealCode: node.id, shopCode: activeKey }
    }
    console.log("params", params)
    setCurTreeItem(item)
    setQuotaParams(params)
    queryQuota(params)
    //重置表格勾选状态
    tableRef.current.reset()

  }
return (
            <div>
                {
                        treeData.length == 0 ? <Empty /> : <Tree
                        defaultExpandParent
                        onSelect={selectTree}
                        treeData={treeData}
                        titleRender={renderTitle}
                      />
                  }



                <QuotaTable
                      ref={tableRef}
                      columns={columns}
                      loading={tableLoading}
                      dataSource={tableList}
                      total={total}
                      queryQuotaByPage={queryQuotaByPage}
                      getSelectedTableIds={getSelectedTableIds}
                      renderTitleRtConts={
                        <Space >
                          <Button
                            type="primary"
                            disabled={disabledAddBtn()}
                            onClick={addQuota}
                          >
                            添加定额
                          </Button>
                          <Button
                            type="primary"
                            disabled={tableSelectedIds.length > 0 ? false : true}
                            onClick={copyQuota}
                          >
                            复制
                            </Button>
                          <Button
                            type="primary"
                            disabled={tableSelectedIds.length > 0 ? false : true}
                            onClick={remove}
                          >
                            移除
                          </Button>
                          <Popover
                            showCancel={false}
                            title={FilteredForm}
                            trigger="click"
                          >
                            <Iconfont
                              type="icon-guolv"
                              className="filter" />
                          </Popover>
                        </Space>
                      }>
                    </QuotaTable>

        )
    </div>

tableRef.current获取到子组件的实例以后直接调用reset方法就可以解决这个问题

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-14 23:43:36  更:2022-04-14 23:46:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:48:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码