在React中按类名称获取最接近的父元素 [英] Get closest parent element by class name in 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-body
的div
元素.
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: block
和display: 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屋!