簡體   English   中英

在 React 中通過類名獲取最接近的父元素

[英]Get closest parent element by class name in React

使用 React,如何使用特定類名引用父元素最接近的元素?

代碼如下:

const Skill = props => (
<div className="skill-card">
    <div className="skill-header">
        <div className="skill-header-text">
            <div className="skill-header-img-container">
                <img src={require('../../img/projects/skills/' + props.skill.image)} alt={props.skill.name} className="skill-image" />
            </div>
            <div className="skill-heading"><h2 className="skill-name">{props.skill.name}</h2></div>
        </div>
        <div className="skill-header-icon">
            <FontAwesomeIcon icon={"angle-" + props.angle} onClick={props.click} />
        </div>
    </div>
    <div className="skill-body">
        ...
    </div>
</div>
);

class Skills extends Component {
    ...

    handleClick = () => {
        // Add style to the closest skill-body in here!
    }
}

在這種情況下,一旦我單擊FontAwesomeIcon ,我希望打開帶有 className skill-bodydiv元素。

首先,我認為使用狀態會很好,但到目前為止,單擊FontAwesomeIcon后所有skill-body元素都會打開。 我的方法只是為skill-body添加樣式( display: blockdisplay: none )。

如何使用handleClick引用Component函數中的skill-body

編輯:使用了 HMR 的功能組件示例,但我仍然卡住了。

const Skills = ({ skills }) => (
<div>
    {skills.map(skill => (
        <SkillContainer key={skill._id} skill={skill} />
    ))}
</div>
);

const Skill = ({ skill, open, toggle, data }) => (
    <div>
        <h4 onClick={toggle}>skill: {skill} {data.name}</h4>
        {open && <div>{data.description}</div>}
    </div>
);

const SkillContainer = ({ skill }) => {
    const [open, setOpen] = React.useState(false);
    const [data, setData] = React.useState({ skills: [] });

    const toggle = React.useCallback(() => setOpen(open => !open), []);

    useEffect(() => {
        const fetchData = async () => {
            const result = await         
                axios("http://localhost:5000/api/skills/");

        setData(result.data);
    }

    fetchData();
}, []);

return React.useMemo(() => Skill({ skill, open, toggle, data }), [open, 
skill, toggle, data]);
}

export default Skills;

到目前為止,通過閱讀useHook文檔達到了這一點。 我想做的是用axios收集數據,然后用它設置內容。

您可以在功能組件中使用 State,如下所示:

 const Skills = ({ skills, loading }) => loading ? ( 'loading' ) : ( <div> {skills.map(skill => ( <SkillContainer key={skill._id} skill={skill} /> ))} </div> ) const Skill = ({ skill, open, toggle }) => ( <div> <h4 onClick={toggle}> skill: {skill.completed} {skill.id} </h4> {open && <div>{skill.title}</div>} </div> ) const SkillContainer = ({ skill }) => { const [open, setOpen] = React.useState(false) const toggle = React.useCallback( () => setOpen(open => !open), [] ) return React.useMemo( () => Skill({ skill, open, toggle }), [open, skill, toggle] ) } //savety to not set state when component is no longer mounted const useIsMounted = () => { const isMounted = React.useRef(false) React.useEffect(() => { isMounted.current = true return () => (isMounted.current = false) }, []) return isMounted } const SkillsContainer = () => { const [result, setResult] = React.useState({ loading: true, data: [] }) const isMounted = useIsMounted() React.useEffect(() => { const fetchData = () => { //cannot use async await here because Stack Overflow // uses old babel axios .get('https://jsonplaceholder.typicode.com/todos') .then(result => { if (isMounted.current) { //do not set data if component is no longer mounted setResult({ loading: false, data: result.data }) } }) } fetchData() }, [isMounted]) return React.useMemo( () => Skills({ skills: result.data, loading: result.loading }), [result] ) } //render app ReactDOM.render( <SkillsContainer />, document.getElementById('root') )
 <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.19.2/axios.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>

類版本有點冗長:

 class SkillsContainer extends React.PureComponent { state = { loading: true, //should do error here as well result: [] } fetchData = ( length //arrow function auto bind to this ) => new Promise(r => setTimeout(() => r(length), 2000) ).then(l => this.setState({ loading: false, result: [...new Array(l)].map((_, i) => i+1) }) ) //if your skills array changes based on props: // example here: https://reactjs.org/docs/react-component.html#componentdidupdate componentDidUpdate(prevProps) { if (this.props.length !== prevProps.length) { this.fetchData(this.props.length) } } //fetch data on mount componentDidMount() { this.fetchData(this.props.length) } render() { return this.state.loading ? 'loading' : Skills({ skills: this.state.result }) } } const Skills = ({ skills }) => ( <div> {skills.map((skill, id) => ( <SkillContainer key={id} skill={skill} /> ))} </div> ) const Skill = ({ skill, open, toggle }) => ( <div> <h4 onClick={toggle}>skill: {skill}</h4> {open && <div>extra</div>} </div> ) class SkillContainer extends React.PureComponent { state = { open: false } toggle() { this.setState({ open: !this.state.open }) } render() { return Skill({ skill: this.props.skill, open: this.state.open, toggle: this.toggle.bind(this) }) } } //render app ReactDOM.render( <SkillsContainer length={2} />, document.getElementById('root') )
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>

該代碼使用條件渲染,但您也可以使用 props 來設置 className

我想將技能體元素 ref 傳遞給父級,以便您可以處理元素的樣式。 希望下面的代碼能完成你需要的事情。

class Skill extends React.Component {

    render() {
        return (
            <div className="skill-card">
            <div className="skill-header">
                <div className="skill-header-icon">
                   <div onClick={() => this.props.click(this.skillBodyEle)}>Header Icon</div>
                </div>
            </div>
            <div
            ref={e => this.skillBodyEle = e}
            className="skill-body">
                Skill Body
            </div>
        </div>
            );
    }
}

class Skills extends React.Component {
    handleClick = (skillBodyEle) => {
        if (skillBodyEle.hidden) {
            skillBodyEle.hidden = false;
        } else {
            skillBodyEle.hidden = true;
        }
      };
      render() {
          return (
          <Skill 
            click={this.handleClick} 
          />
          );
      }
}

在 handleClick() 內部,您可以操作 DOM 使其工作:

const ele = document.getElementsByClassName('skill-body')[0];

if (ele.visibility === 'hidden') {
  ele.visibility = 'visible';
}
else {
  ele.visibility = 'hidden';
}

但是,我建議像其他答案一樣使用 props/state 來完成您的任務。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM