Reactjs如何在map函数中使用ref?

24
我正在遍历一个数组,并为每个条目显示一个带文本的按钮。假设我想要在点击按钮时,下方的文本将变成红色。如何定位按钮的兄弟元素?我尝试使用ref,但由于这是映射的JSX,只有最后一个ref元素将被声明。
这是我的代码:
class Exams extends React.Component {
    constructor(props) {
        super()
        this.accordionContent = null;
    }
    state = {
        examsNames: null, // fetched from a server
    }
    accordionToggle = () => {
        this.accordionContent.style.color = 'red'
    }
    render() {
        return (
            <div className="container">
                {this.state.examsNames && this.state.examsNames.map((inst, key) => (
                    <React.Fragment key={key}>
                        <button onClick={this.accordionToggle} className="inst-link"></button>
                        <div ref={accordionContent => this.accordionContent = accordionContent} className="accordionContent">
                            <p>Lorem ipsum dolor sit amet consectetur, adipisicing elit. Aperiam, neque.</p>
                        </div>    
                    </React.Fragment>
                ))}
            </div>
        )
    }
}


export default Exams;
如上所述,结果是每次按钮被点击时,将针对最后一个按钮附加的段落进行操作。
提前致谢。

使用this.accordionContent作为一个数组。 - Prakash Sharma
注意:有关 useRef 钩子,请参见此答案 https://dev59.com/ZFQI5IYBdhLWcg3w8wWR#55105849。 - Marcelo Potty
4个回答

26

this.accordionContent初始化为数组

constructor(props) {
    super()
    this.accordionContent =[];
}

并将ref设置为以下内容

<div ref={accordionContent => this.accordionContent[key] = accordionContent} className="accordionContent">

我还发现了另一种方法,不确定它是否像这个好,但我会在这里发布。 - sir-haver

2
这是我基于你上面的代码示例创建的工作代码片段。
链接示例是一个“实际”的手风琴,即显示和隐藏相邻内容。
(请参见下面的代码片段以将其变为红色) https://codepen.io/PapaCodio/pen/XwxmvK?editors=0010
代码片段 初始化引用数组:
constructor(props) {
    super();
    this.accordionContent = [];
}

将引用添加到引用数组中,使用键:
<div ref={ref => (this.accordionContent[key] = ref)} >

将密钥通过onClick传递给切换函数。最初的回答。
 <button onClick={() => this.accordionToggle(key)} >

最初的回答中提到,在切换函数内最终引用该键。请参考该键。
accordionToggle = key => {
    this.accordionContent[key].style.color = 'red'
};

1
在下面的示例中,我使用一个refs数组,使用useRef进行初始化,以便在重新渲染时保持不变。然后,在第一次渲染<Wrapper>时填充该数组,从此之后,所有使用React.createRef()map内创建的ref都将被缓存在refs中,并准备好在<Wrapper>重新渲染时使用。
每个动态的ref(来自refs数组)都被分配为每个子节点的属性:

const Wrapper = ({children}) => {
    const refs = React.useRef([]);

    // as the refs are assigned with `ref`, set each with a color "red"
    React.useEffect(() => {
      refs.current.map(ref => { 
        // no support here for optional chaining: ref?.current?.style.color
        if(ref.current) ref.current.style.color = 'red'
      })
    }, [refs]);

    // iterate the children and create a ref inide the "refs" array,
    // if one was not already added for this child's index.
    // use "cloneElement" to pass that ref to the children
    const withProps = React.Children.map(children, (child, i) => {
        // no support here for ?? instead of ||
        refs.current[i] = refs.current[i] || React.createRef();
        return React.cloneElement(child, {ref: refs.current[i] })
    });

    // no support for <> instead of useless `div` wrapper
    return <div>{withProps}</div>
};

ReactDOM.render(<Wrapper>
  <button>1</button>
  <button>2</button>
  <button>3</button>
</Wrapper>, document.body)
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>


1

我找到了一种不使用ref的方法,通过使用map的key属性:

 accordionToggle = (key) => {
        console.log(key)
        var a = document.getElementsByClassName('accordionContent')
        a[key].style.color = 'red'
    }

我不确定这样访问dom是否比直接使用引用(refs)来定位元素更好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接