React:基于 props 的设置和更新

React: Setting and updating based on props

目前我面临的问题是,我想在 prop 初始化或更改为某个值后立即更改 React 中子组件的状态。如果我用一个简单的 if 查询来解决这个问题,那么我当然会得到一个无限循环,因为组件会被一遍又一遍地渲染。

组件(父):

function App() {
    const [activeSlide, setActiveSlide] = useState(0);

    function changeSlide(index) {
        setActiveSlide(index);
    }

    return (
        <div className="app">
            <div className="app__nav">
                <Button icon="FiSun" handler={changeSlide} active={activeSlide} index="0" />
                <Button icon="FiSettings" handler={changeSlide} active={activeSlide} index="1" />
            </div>
        </div>
    );
}

组件(子):

function Button(props) {
    const Icon = Icons[props.icon];
    const [activeClass, setActiveClass] = useState("");

    // This attempts an endless loop
    if(props.active == props.index) {
        setActiveClass("active");
    }

    function toggleView(e) {
        e.preventDefault();
        props.handler(props.index);
    }

    return(
        <button className={activeClass} data-index={props.index} onClick={toggleView}>
            <Icon />
        </button>
    )
}

这里有一个明智而简单的方法吗?我的想法是将 if-query 写入 return() 并因此生成两个不同的输出,即使我实际上想避免这种情况

尝试使用钩子useEffect来防止无限循环。 (https://fr.reactjs.org/docs/hooks-effect.html)

或者使用回调钩子。 (https://fr.reactjs.org/docs/hooks-reference.html#usecallback)

试试这个,然后告诉我它是否适合你:

function App() {
    const [activeSlide, setActiveSlide] = useState(0);

    const changeSlide = useCallback(() => {
        setActiveSlide(index);
    }, [index]);

    return (
        <div className="app">
            <div className="app__nav">
                <Button icon="FiSun" handler={changeSlide} active={activeSlide} index="0" />
                <Button icon="FiSettings" handler={changeSlide} active={activeSlide} index="1" />
            </div>
        </div>
    );
}

这个用处很大of useEffect

您可以将 if 语句替换为;

const {active, index} = props

useEffect(_ => {
    if(active == index) {
        setActiveClass("active");
    }
 }, [active])

函数中的最后一项是依赖项,所以 useEffect 只会 运行 如果活动道具发生变化。

当状态或道具发生变化时,React 会自动重新渲染组件。如果您只是使用 activeClass 来管理 className,您可以像这样移动 className 中的条件并摆脱状态。

<button className={props.active === props.index ? 'active' : ''} data-index={props.index} onClick={toggleView}>
  <Icon />
</button>

但是,如果您仍想在子组件中使用状态,则可以使用 useEffect 挂钩来更新子组件中的状态。

React 文档有一个很好的清单 here 用于确定某物是否属于状态。这是列表:

  1. 它是通过道具从 parent 传入的吗?如果是这样,它可能不是状态。
  2. 它是否随着时间的推移保持不变?如果是这样,它可能不是状态。
  3. 你能根据组件中的任何其他状态或道具计算它吗?如果是,则不是状态。

活动 class 不符合该标准,应该在需要时计算而不是放入状态。

return(
  <button className={props.active == props.index ? 'active' : ''} data-index={props.index} onClick={toggleView}>
    <Icon />
  </button>
)