如何使用 React 和 Typescript 在 useEffect 钩子中设置状态?

IT技术 reactjs typescript
2021-05-24 15:16:11

当用户使用 React 和 Typescript 位于“/items/:itemId”页面时,我想将正确的属性从 16px 更改为 40px。

下面是我的组件片段,

const root = () => {
    <PopupContextProvider>
        <App/>
    </PopupContextProvider>
}


export const PopupContextProvider = ({ children }: any) => {
    return (
        <popupContext.Provider value={context}>
            {children}
                {(condition1 || condition2) && (
                    <Popup onHide={dismiss} />
                )}
        </popupContext.Provider>
    );
}


export function Popup({ onHide }: Props) {
    return (
        <Dialog>
            <DialogBody>
                <span>Title</span>
                <Description/>
            </DialogBody>
            <Actions>
                <span>Hide</span>
            </Actions>
        </Dialog>
    );
}


const Dialog = styled.div`
    position: fixed;
    right: 16px;//want to change this to 40px if user is in page 
    "/items/:itemId"
    display: flex;
    flex-direction: column;
`;

我尝试过什么?

export function Popup({ onHide }: Props) {
    const location = useLocation();
    const [isView, setIsView] = React.useState(false);
    if (location.pathname === '/items/:itemId') {
        setIsView(true);
        //Here, it doesn't change to true.
        //How can I do the same in useEffect or something that updates
    }
    return (
        <Dialog isView={isView}>
            <DialogBody>
                <span>Title</span>
                <Description/>
            </DialogBody>
            <Actions>
                <span>Hide</span>
            </Actions>
        </Dialog>
    );
}


const Dialog = styled.div<isView?:boolean>`
    position: fixed;
    ${({ isView }) => isView && 'right:  40px;'}
    display: flex;
    flex-direction: column;
`;

即使用户在页面“/items/:itemId”中,我上面的代码也不会用正确的 40px 更新弹出窗口的位置。

我不确定出了什么问题。有人可以帮我弄这个吗?谢谢。

编辑:

我根据提供的答案之一进行了尝试。

export function Popup({ onHide }: Props) {
    const location = useLocation();
    const [isView, setIsView] = React.useState(false);
    React.useEffect(() => {
        const match = matchPath(
            location.pathname,
            '/items/:itemId'
        );
        if (match) { //it doesnt get it into this condition since match is 
            //null
            setIsScheduleView(true);
        }
    }, []);
    return (
        <Dialog isView={isView}>
            <DialogBody>
                <span>Title</span>
                <Description/>
            </DialogBody>
            <Actions>
                <span>Hide</span>
            </Actions>
        </Dialog>
    );
}
3个回答

您可以使用 useEffect 钩子来实现您想要的副作用。

首先,您可以将“位置”变量作为 useEffect 钩子中的依赖项之一,如下所示。

useEffect(() => {

// do your if condition
// set isView state as side effect

},[location]);

其次,我认为你的情况不正确。

location.pathname 将不等于 '/items/:itemId' 因为:itemId是一个动态参数。因此,您可以选择使用包含方法来检查它是否是您的 url,或者您可以添加一个包装器,该包装器将首先解析为“/items”,然后解析为“/items/:itemId”。当路由进入包装器时,您可以进行样式设置。

编辑:或者更好的是,您可以使用 react-router 的 matchPath api,因为@ludwiguer 也提到过来匹配您的路径。

正如@Kevin Moe Myint Myat 在他的回答中所解释的那样。您的条件不正确,因为其中包含动态 ID。因此,您可以检查是否/items使用了包含方法,如果this.props.match可用,则可以使用它来检查参数 itemId 是否存在。像 一样this.props.match.params.itemId,您可以&在 useEffect 中使用 AND运算符将其与先前的条件结合使用

我想你正在使用react-router,如果是这样你可以使用matchPath https://reactrouter.com/web/api/matchPath

import { matchPath } from 'react-router';

setIsView(
 !!matchPath(
    this.props.location.pathname, 
    {path: 'items/:itemId'}
  ));