[英]How to properly conditionally render child component in react
I have the following components: (AddBookPanel contains the AddBookForm)我有以下组件:(AddBookPanel 包含 AddBookForm)
I need to have the ability to display the form on click of the 'AddBookButton', and also have the ability to hide the form while clicking the 'x' button (img in AddBookForm component), however the component doesn't seem to load properly, what could be wrong here?我需要能够在单击“AddBookButton”时显示表单,并且还能够在单击“x”按钮(AddBookForm 组件中的 img)时隐藏表单,但是该组件似乎无法加载正确的,这里可能有什么问题? What do you think is the best way to organize this?你认为最好的组织方式是什么?
import { AddBookButton } from './AddBookButton';
import { AddBookForm } from './AddBookForm';
import { useState } from 'react';
export const AddBookPanel = () => {
const [addBookPressed, setAddBookPressed] = useState(false);
return (
<div>
<div onClick={() => setAddBookPressed(!addBookPressed)}>
<AddBookButton />
</div>
<AddBookForm initialFormActive={addBookPressed} />
</div>
);
};
import { useState } from 'react';
interface AddBookFormProps {
initialFormActive: boolean;
}
export const AddBookForm: React.FC<AddBookFormProps> = ({
initialFormActive,
}) => {
const [isFormActive, setIsFormActive] = useState(initialFormActive);
return (
<>
{isFormActive && (
<div className="fixed box-border h-2/3 w-1/3 border-4 left-1/3 top-24 bg-white border-slate-600 shadow-xl">
<div className="flex justify-between bg-slate-400">
<div>
<p className="text-4xl my-5 mx-6">Add a new Book</p>
</div>
<div className="h-16 w-16 my-3 mx-3">
<button onClick={() => setIsFormActive(!isFormActive)}>
<img
src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/OOjs_UI_icon_close.svg/1200px-OOjs_UI_icon_close.svg.png"
alt="close-button"
className="object-fit"
></img>
</button>
</div>
</div>
<div className="flex-col">
<div className="flex justify-between my-10 ml-5 text-xl">
<input type="text" placeholder="book name"></input>
</div>
</div>
</div>
)}
</>
);
};
You're always rendering the AddBookForm
.您总是在渲染AddBookForm
。 That means in the initial render the useState
is called with false
.这意味着在初始渲染中使用false
调用useState
。 Since you never call setIsFormActive
it is now stuck as "do not render".由于您从不调用setIsFormActive
它现在被困为“不渲染”。
Just don't use the useState
and use the property initialFormActive
directly.只是不要使用useState
并直接使用属性initialFormActive
。 And maybe rename it to isFormActive
.也许将其重命名为isFormActive
。 Let the parent handle the state change.让父处理 state 更改。
import { AddBookButton } from './AddBookButton';
import { AddBookForm } from './AddBookForm';
import { useState } from 'react';
export const AddBookPanel = () => {
const [addBookPressed, setAddBookPressed] = useState(false);
return (
<div>
<div onClick={() => setAddBookPressed(!addBookPressed)}>
<AddBookButton />
</div>
<AddBookForm initialFormActive={addBookPressed} onClose={() => setAddBookPressed(false)} />
</div>
);
};
import { useState } from 'react';
interface AddBookFormProps {
initialFormActive: boolean;
onColse: () => void;
}
export const AddBookForm: React.FC<AddBookFormProps> = ({
initialFormActive,
onClose,
}) => {
// const [isFormActive, setIsFormActive] = useState(initialFormActive); don't use this frozen state, allow the parent to control visibility
return (
<>
{initialFormActive && (
<div className="fixed box-border h-2/3 w-1/3 border-4 left-1/3 top-24 bg-white border-slate-600 shadow-xl">
<div className="flex justify-between bg-slate-400">
<div>
<p className="text-4xl my-5 mx-6">Add a new Book</p>
</div>
<div className="h-16 w-16 my-3 mx-3">
<button onClick={() => onClose()}>
<img
src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/OOjs_UI_icon_close.svg/1200px-OOjs_UI_icon_close.svg.png"
alt="close-button"
className="object-fit"
></img>
</button>
</div>
</div>
<div className="flex-col">
<div className="flex justify-between my-10 ml-5 text-xl">
<input type="text" placeholder="book name"></input>
</div>
</div>
</div>
)}
</>
);
};
Problem with your code is in how you tied initialFormActive
to inner state of AddBookForm
component.您的代码的问题在于您如何将initialFormActive
到AddBookForm
组件的内部 state 。 When looking at useState inside AddBookForm
it is clear that prop initialFormActive
only affects your initial state, and when looking at your parent component I can clearly see that you passed false as value for initialFormActive
prop, thus initializing state inside AddBookForm
with false value(form will stay hidden).当查看 AddBookForm 中的AddBookForm
时,很明显 prop initialFormActive
只会影响您的初始 state,当查看您的父组件时,我可以清楚地看到您将 false 作为initialFormActive
道具的值,因此在AddBookForm
中使用 false 值初始化 state(表单将保持隐藏)。 Then you expect when you click on button, and when prop value changes(becomes true), that your <AddBookForm />
will become visible, but it will not because you just used initial value(false) from prop and after that completely decoupled from prop value change.然后,您期望当您单击按钮时,并且当道具值更改(变为真)时,您的<AddBookForm />
将变得可见,但这不会因为您只是使用道具的初始值(假),然后完全脱离道具价值变化。
Since you want to control visibility outside of component, then you should attach two props to AddBookForm, isVisible
and toggleVisibiliy
.由于您想控制组件外部的可见性,因此您应该将两个道具附加到 AddBookForm, isVisible
和toggleVisibiliy
。 And do something like this:并做这样的事情:
export const AddBookPanel = () => {
const [addBookPressed, setAddBookPressed] = useState(false);
const toggleAddBookPressed = () => setAddBookPressed(p => !p);
return (
<div>
<div onClick={() => setAddBookPressed(!addBookPressed)}>
<AddBookButton />
</div>
<AddBookForm isVisible={addBookPressed} toggleVisibility={toggleAddBookPressed } />
</div>
);
}; };
export const AddBookForm: React.FC<AddBookFormProps> = ({
isVisible, toggleVisibility
}) => {
return (
<>
{isVisible&& (
<div className="fixed box-border h-2/3 w-1/3 border-4 left-1/3 top-24 bg-white border-slate-600 shadow-xl">
<div className="flex justify-between bg-slate-400">
<div>
<p className="text-4xl my-5 mx-6">Add a new Book</p>
</div>
<div className="h-16 w-16 my-3 mx-3">
<button onClick={toggleVisibility}>
<img
src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/OOjs_UI_icon_close.svg/1200px-OOjs_UI_icon_close.svg.png"
alt="close-button"
className="object-fit"
></img>
</button>
</div>
</div>
<div className="flex-col">
<div className="flex justify-between my-10 ml-5 text-xl">
<input type="text" placeholder="book name"></input>
</div>
</div>
</div>
)}
</>
);
};
Try this one试试这个
import { useState } from 'react';
interface AddBookFormProps {
initialFormActive: boolean;
}
export const AddBookForm: React.FC<AddBookFormProps> = ({
initialFormActive,
}) => {
const [isFormActive, setIsFormActive] = useState(initialFormActive);
return (
<>
{isFormActive ? (
<div className="fixed box-border h-2/3 w-1/3 border-4 left-1/3 top-24 bg-white border-slate-600 shadow-xl">
<div className="flex justify-between bg-slate-400">
<div>
<p className="text-4xl my-5 mx-6">Add a new Book</p>
</div>
<div className="h-16 w-16 my-3 mx-3">
<button onClick={() => setIsFormActive(!isFormActive)}>
<img
src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a0/OOjs_UI_icon_close.svg/1200px-OOjs_UI_icon_close.svg.png"
alt="close-button"
className="object-fit"
></img>
</button>
</div>
</div>
<div className="flex-col">
<div className="flex justify-between my-10 ml-5 text-xl">
<input type="text" placeholder="book name"></input>
</div>
</div>
</div>
):(<><h1>Solution when it is false</h1></>)}
</>
);
};
You need to add your JSX for true
condition.您需要添加您的 JSX 以获得true
条件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.