javascript - 在 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
,我希望打开div
带有 className 的元素。skill-body
首先我认为使用状态会很好,但到目前为止,所有skill-body
元素都会在单击FontAwesomeIcon
. 我的方法只是向skill-body
(display: block
和display: none
) 添加样式。
我怎样才能用 ? 引用skill-body
里面的Component
's 函数handleClick
?
编辑:使用了 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
推荐阅读
- java - 如何通过 HtmlUnitDriver 和 HtmlUnit 无头浏览器在 Pick a Category (US) 下创建以不同方式呈现的项目列表?
- kotlin - TreeSet中的HeadSet、TailSet、SubSet
- react-native - 反应原生
- asp.net - 使用自定义验证器控件条件是入口应该是数字和字母
- java - clientHello 中的 TLS 1.2 客户端密码列表对于不同的 https 服务器主机的顺序不同
- github-api - 无法使用 Github API 向拉取请求发布评论
- typescript - RaphaelJS 不会使用 typescript 构建
- ios - iOS 推送通知和 Testflight 使用 ..p8 证书和 apn
- azure - Azure 逻辑应用程序 - 通过 powershell 更新 Blob API 连接
- java - 如何在责任链中跳过空值?