首页 > 解决方案 > 引用特定列的引用数组存在问题

问题描述

我无法refs工作。我想渲染几列,然后渲染放置在右列上的项目。例如,声明的 items:const items = [0, 2, 5]应该像这样在网格上呈现(假设第一列的索引为 0):

这就是我想要实现的

我想refs在列上使用来获取列位置(使用 getBoundingClientRect() 只是为了这个想法)但是columnsRefs[index].current即使componentDidMount按照推荐的方式分配了参考,我也是空的。这是我的代码:

import * as React from 'react';

export const GridColumn = (props: {forwardedRef?: any }) => (
    <div style={{borderRight: "1px solid #ababab", width: "20px", height: "200px"}} ref={props.forwardedRef}></div>
);

interface GridProps {
}

export class Grid extends React.Component<GridProps, any> {
    public constructor(props: GridProps) {
        super(props);
        this.state = {
            columns: []
        }
    }

    private columnRefs = new Array<React.RefObject<HTMLDivElement>>();

    public componentDidMount(){
        // setup the columns with refs
        const columnIds = [0, 1, 2, 3, 4, 5, 6, 7];
        const columns = columnIds.map(id => {
            const ref = React.createRef<HTMLDivElement>();
            this.columnRefs.push(ref);
            return (<GridColumn forwardedRef={ref}/>)
        });

        this.setState({columns: columns});
    }

    public render() {
        // setup the items
        const items = [
            0, 2, 5
        ]

        let elements = items.map(item => {
            if(this.columnRefs[item] && this.columnRefs[item].current) {
                return (
                    <div style={{backgroundColor: "blue", 
                        opacity: 0.5, 
                        position: "absolute",
                        width: "10px", 
                        height: "20px",
                        left: `${this.columnRefs[item].current.getBoundingClientRect().left}px`,
                        top: "0"}}>
                    </div>);
            }
            else {
                return undefined;
            }
        });

        return (
        <div style={{width: "500px", height: "200px", position: "relative"}}>
            {elements}
            <div style={{display: "flex"}}>
                {this.state.columns}
            </div>
        </div>);
    }
}

我做错了什么,以至于条件render if(this.columnRefs[item] && this.columnRefs[item].current)总是错误的?

标签: javascriptreactjstypescript

解决方案


您不应该将渲染的组件存储在状态中。状态用于您要转换为标记的数据。这是带有注释的修改代码:

// Now component properly forwards ref
const GridColumn = React.forwardRef((props, ref) => (
  <div
    style={{ borderRight: "1px solid #ababab", width: "20px", height: "200px" }}
    ref={ref}
    {...props}
  ></div>
));

class Grid extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      columns: [1,2,3,4,5,6,7,8,9],
      rendered: false
    };
  }

  // When you want to use collection of refs, you can set up your own storage for them
  // I use Set because it will prevent duplicates
  // It is important that when component will be removed it's ref will turn into `null`, so you will have to check if your div still exists
  columnRefs = new Set();

  componentDidUpdate() {
    // you will see your refs set in console on each render
    console.debug(this.columnRefs);
  }
  
  componentDidMount() {
    // You need to rerender to render something from refs
    this.setState({rendered: true});
  }
  
  render() {
    const items = [0, 2, 5];

    let elements = items.map((item) => {
      // turn set into array and filter out null
      let refArray = [...this.columnRefs].filter(Boolean);
      if (refArray[item]) {
        return (
          <div
            key={item}
            style={{
              backgroundColor: "blue",
              opacity: 0.5,
              position: "absolute",
              width: "10px",
              height: "20px",
              left: `${refArray[item].getBoundingClientRect().left}px`,
              top: "0",
            }}
          ></div>
        );
      } else {
        return undefined;
      }
    });

    return (
      <div style={{ width: "500px", height: "200px", position: "relative" }}>
        {elements}
        <div style={{ display: "flex" }}>
          {/* We use here ref callback to store forwarded ref into out set */}
          {this.state.columns.map((item) => (
            <GridColumn key={item} ref={(ref) => this.columnRefs.add(ref)} />
          ))}
        </div>
      </div>
    );
  }
}

读什么:

例子

可重现且部分固定的示例:https ://jsfiddle.net/moL1sbzj/


推荐阅读