在React中按类名称获取最接近的父元素 [英] Get closest parent element by class name in React

查看:70
本文介绍了在React中按类名称获取最接近的父元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用React,如何使用某些类名引用父元素的最接近元素?

Using React, how do I refer to parent element's closest element with certain classname?

以下代码:

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元素.

In this case, once I click the FontAwesomeIcon, I want the div element with className skill-body to open up.

首先,我认为使用状态会很好,但是到目前为止,所有skill-body元素都将在单击FontAwesomeIcon后打开.我的方法是在skill-body(display: blockdisplay: none)中添加样式.

First I thought that using states would be good, but by far all the skill-body elements will open up upon clicking the FontAwesomeIcon. My approach would be just add stylings to skill-body (display: block and display: none).

如何用handleClick引用Component函数内的skill-body?

使用了HMR的功能组件示例,但我仍然很困惑.

Used HMR's functional component example, and I am still stuck.

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收集数据,然后用它设置内容.

Got to this point so far by reading the useHook documentations. What I want to do, is gather data with axios and then set the content with it.

推荐答案

您可以在诸如此类的功能组件中使用State:

You can use State in functional components like so:

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>

代码使用条件渲染,但是您可以也使用道具来设置className

The code uses conditional rendering but you can use props to set className as well

这篇关于在React中按类名称获取最接近的父元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆