[英]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-body
的div
元素。
首先,我認為使用狀態會很好,但到目前為止,單擊FontAwesomeIcon
后所有skill-body
元素都會打開。 我的方法只是為skill-body
添加樣式( display: block
和display: 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.