Reactjs 使用某些道具触发useEffect()React挂钩,但在效果中引用其他道具

Reactjs 使用某些道具触发useEffect()React挂钩,但在效果中引用其他道具,reactjs,react-hooks,Reactjs,React Hooks,我有一个React用例,其中一个组件获得一个向下传递的类别属性,并且还有一个本地状态值限制。我想要的行为是: 当选择类别时,如果当前高于10,则限制将重置为10 当类别被清除时,如果限制当前低于50,则将其重置为50 当类别保持不变时,用户可以选择所需的任何限制 我在效果挂钩中设置了此行为,如下图所示(更完整的示例): 使用ref跟踪上一个类别如何?它们相当于功能内组件 这样,您可以进行比较,并且仅在类别发生更改时运行效果代码,例如 const prevCat = useRef(null); u

我有一个React用例,其中一个组件获得一个向下传递的
类别
属性,并且还有一个本地状态值
限制
。我想要的行为是:

  • 当选择
    类别
    时,如果当前高于10,则
    限制将重置为10

  • 类别
    被清除时,如果
    限制
    当前低于50,则将其重置为50

  • 类别
    保持不变时,用户可以选择所需的任何
    限制

  • 我在效果挂钩中设置了此行为,如下图所示(更完整的示例):


    使用
    ref
    跟踪上一个类别如何?它们相当于功能内组件

    这样,您可以进行比较,并且仅在类别发生更改时运行效果代码,例如

    const prevCat = useRef(null);
    useEffect(() => {
      if (prevCat.current === category) return;
    
      prevCat.current = category;
      ...
    }, [category, limit]);
    
    切换到管理
    限制
    类别
    ,并将两者传递到组件,而不是使用本地状态。这样,仅当其中一个值更改(或两者都更改)时才会渲染组件

    const initialState={
    类别:正确,
    限额:10
    };
    功能减速机(状态、动作){
    开关(动作类型){
    案例“切换类别”:
    如果(状态类别){
    返回{category:false,limit:Math.min(50,state.limit)};
    }
    否则{
    返回{category:true,limit:Math.max(10,state.limit)};
    }
    案例“设置限制”:
    返回{…状态,限制:action.limit};
    违约:
    抛出新错误();
    }
    }
    函数App(){
    const[state,dispatch]=useReducer(reducer,initialState);
    //React保证分派函数标识是稳定的,并且在重新渲染时不会更改。
    //这就是为什么从useEffect或useCallback依赖项列表中省略是安全的。
    const-toggleCategory=useCallback(()=>dispatch({type:'toggleCategory'}));
    const setLimit=useCallback(limit=>dispatch({type:'setLimit',limit}));
    返回(
    切换类别
    );
    }
    函数列表({category,limit,setLimit}){
    返回(
    setLimit(例如target.value)}>
    {[5,10,25,50,100].map(d=>(
    {d}
    ))}
    类别为{类别?“开”:“关”}
    将显示{limit}项
    );
    }
    
    您可以使用setter的功能版本:

    useEffect(() => {
        setLimit((currentLimit) => {
            if (category && currentLimit > 10) {
              return 10;
            } else if (!category && currentLimit < 50) {
              return 50;
            } else return currentLimit;
        });
      }, [category]);
    
    useffect(()=>{
    设置限制((当前限制)=>{
    如果(类别和当前限制>10){
    返回10;
    }如果(!类别和当前限制<50),则为else{
    返回50;
    }否则返回电流限制;
    });
    },[类别];
    
    const prevCat = useRef(null);
    useEffect(() => {
      if (prevCat.current === category) return;
    
      prevCat.current = category;
      ...
    }, [category, limit]);
    
    const initialState = {
        category: true,
        limit: 10
    };
    
    function reducer(state, action) {
        switch (action.type) {
        case 'toggleCategory':
            if (state.category) {
                return {category: false, limit: Math.min(50, state.limit)};
            }
            else {
                return {category: true, limit: Math.max(10, state.limit)};
            }
        case 'setLimit':
            return {...state, limit: action.limit};
        default:
            throw new Error();
        }
    }
    
    function App() {
        const [state, dispatch] = useReducer(reducer, initialState);
        // React guarantees that dispatch function identity is stable and won’t change on re-renders.
        // This is why it’s safe to omit from the useEffect or useCallback dependency list.
        const toggleCategory = useCallback(() => dispatch({type: 'toggleCategory'}));
        const setLimit = useCallback(limit => dispatch({type: 'setLimit', limit}));
        return (
            <div className="App">
                <button onClick={toggleCategory}>Toggle category</button>
                <List {...state} setLimit={setLimit} />
            </div>
        );
    }
    
    function List({ category, limit, setLimit }) {
        return (
            <div>
                <select value={limit} onChange={e => setLimit(e.target.value)}>
                    {[5, 10, 25, 50, 100].map(d => (
                        <option key={d}>{d}</option>
                    ))}
                </select>
                <div>Category is {category ? "on" : "off"}</div>
                <div>Would show {limit} items</div>
            </div>
        );
    }
    
    useEffect(() => {
        setLimit((currentLimit) => {
            if (category && currentLimit > 10) {
              return 10;
            } else if (!category && currentLimit < 50) {
              return 50;
            } else return currentLimit;
        });
      }, [category]);