更好地使用useEffect挂钩,因为不需要使用回调

问题描述

我已经编写了以下React组件,它对依赖项和需要的内容很混乱

useCallback

我的问题是:我对钩子有什么误解,认为我一直需要在哪里使用此useCallback

const TagPicker = ({ value,defaultValue,tags,updateTags }) => {
    const thisPicker = useRef(null);
    const thisInput = useRef(null);

    // Managing Tags
    const [ selectedTags,setSelectedTags ] = useState(value || defaultValue);

    const getIds = useCallback(() => {
        let ids = [];
        for(let x in selectedTags) {
            ids.push(selectedTags[x].id);
        }

        return ids;
    },[ selectedTags ]);

    const addTag = useCallback(tag => {
        let ids = getIds();
        if(!ids.includes(tag.id)) setSelectedTags([ ...selectedTags,tag ]);
    },[ selectedTags,getIds ]);

    const removeTag = tag => {
        let ids = getIds();
        if(ids.includes(tag.id)) setSelectedTags([ ...selectedTags].filter(t => (t.id !== tag.id)));
    }

    // Typed text / Filtered List
    const [ text,setText ] = useState('');
    const [ filteredList,setFilteredList ] = useState([]);

    useEffect(() => {
        let ids = getIds();
        if(text.length) {
            let filteredTags = tags.filter(tag => (!ids.includes(tag.id)));
            setOpen(true);
            let list = [];
            for(let x in filteredTags) {
                if(filteredTags[x].title.toLowerCase().includes(text.toLowerCase())) list.push(filteredTags[x]);
            }
            setFilteredList(list);
        } else {
            setOpen(false);
            setFilteredList([])
        }
    },text,getIds ]);

    useEffect(() => {
        updateTags(selectedTags);
    },[ updateTags,selectedTags ]);

    // Toggling dropdown menu
    const [ open,setOpen ] = useState(false);

    useEffect(() => {
        if(open) getCoordinates(thisPicker);
    },[ open ]);

    // Handling Coordinates
    const [ coords,setCoords ] = useState(null);

    const getCoordinates = ({ current }) => { 
        if(current) {
            const rect = current.getBoundingClientRect();
            setCoords({
                left: rect.x,top: rect.y + window.scrollY + 40
            });
        }
    }

    useEffect(() => {
        window.addEventListener('resize',() => getCoordinates(thisPicker));
        return () => window.removeEventListener('resize',() => getCoordinates(thisPicker));
    },[]);

    // Handle Enter
    const handleEnter = useCallback(e =>  {
        if(e.keyCode === 13 && text) {
            if(filteredList.length) addTag(filteredList[0]);
            else addTag({
                id: Math.random(),title: text
            });
            setText('');
            setOpen(false);
        }
    },[ addTag,filteredList ]);

    useEffect(() => {
        let el = thisInput.current;
        el.addEventListener('keyup',e => handleEnter(e));
        return () => el.removeEventListener('keyup',e => handleEnter(e));
    },[ handleEnter ]);

    return(
        <div className='tag-picker' ref={thisPicker}>
            <input type='text' value={text} onChange={e => setText(e.target.value)} ref={thisInput} />
            <div className='selected-tags'>
                { selectedTags.map(tag => (
                    <Tag tag={tag} key={tag.id} removeTag={removeTag} />
                )) }
            </div>
            { open ? 
                <Portal>
                    <List text={text} items={filteredList} onSelect={addTag} setOpen={setOpen} coords={coords} />
                </Portal>
            : null }
        </div>
    );
};

解决方法

您的第一个useEffect存在一些问题。它具有一个额外的依赖项selectedTags。 如果您不使用useCallback来包装回调,则效果的确取决于selectedTags。如果您使用useCallback,则效果仅取决于回调。

实际上,它们的含义是相同的。如果useCallback的依存关系发生更改,则回调也将重新计算。因此,selectedTags的更改将触发回调(您的getIds)的更改,并触发以下效果:如果没有useCallback,则将依赖项直接放在useEffect的依赖项数组中因此它们的更改会直接触发效果。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...