如何使useEffect根据变量值反应钩子重新渲染?

时间:2020-03-16 16:30:26

标签: javascript reactjs axios react-hooks use-effect

所以我得到了这个组件:

export default function () {
    const [todos, setTodos] = useState([]);


    useEffect(() => {
        function populateTodos () {
            axios.get(`http://localhost:8000/api/all-todos`)
                .then(res => setTodos(res.data))
                .catch(err => console.log(err));
        }

        populateTodos();
    }, []);

    console.log(todos);

    return (
        <div>
            ...
        </div>
    );
}

我正在使用useEffect钩子从数据库中获取所有待办事项,并且工作正常。问题是,我每次修改todos数组(例如添加,删除或更新)时,都不知道如何使用useEffect来触发重新渲染。如果我为useEffect的依赖项数组提供todos变量,则会在控制台中记录一个无限循环。 每当useEffect数组更新时,如何使用todos触发重新渲染?

2 个答案:

答案 0 :(得分:1)

问题在于useEffect内部没有逻辑,请参见下面的代码

    const [todos, setTodos] = useState([]);

    useEffect(() => {
        setTodos([1])
    }, [todos])

这也将产生无限循环。但是我们总是给予相同的价值。问题是,当它更新时,依赖项为true,因此它再次开始执行useEffect()。您必须提出一些具体的逻辑,例如length被更改,或者您可以采用一种新的状态,就像下面这样

    const [todos, setTodos] = useState([]);
    const [load, setLoad] = useState(false);

    useEffect(() => {
        function populateTodos () {
            axios.get(`http://localhost:8000/api/all-todos`)
                .then(res => setTodos(res.data))
                .catch(err => console.log(err));
        }

        populateTodos();
    }, [load])

    console.log(todos)
    return (
        <div>
            <button
            onClick={() => {
                todos.push(1)
                setLoad(!load)
            }}
            >cilck</button>
        </div>
    );

答案 1 :(得分:0)

可以通过获取父组件中的待办事项,然后将结果作为prop传递给依赖于它的useEffect的子组件,来提升状态。为了更新列表,必须在父组件中调用任何CRUD操作(但是您可以通过将这些函数传递给子组件来触发子组件的修改)。

否则,这对于Redux也是一个很好的应用程序。您将能够使用Redux fetch操作初始化组件,以对任何组件执行的所有CRUD操作填充存储,还可以通过修改reducer的API响应来更新存储。然后,您可以将商店用作useEffect依赖项,以更新组件的本地待办事项状态。

// State
const [todos, setTodos] = useState(null);
// Redux Stores 
const todoStore = useSelector(state => state.todoStore);
// Redux Dispatch
const dispatch = useDispatch();
// Lifecycle: initialize the component's todolist
useEffect(() => {
    if (!todos) {
        // your Redux Action to call the API fetch & modify the store
        dispatch(fetchTodos); 
    }
}, [dispatch, todos]
// Lifecycle: update the todolist based on changes in the store
// (in this case I assume the data is populated into todoStore.items)
useEffect(() => {
    if (todoStore.items.length > 0) {
        setTodos(todoStore);
    }
}, [todoStore.items]

return {
    <div>{ todos.map((todo, index) => <li key={'todo_'+index}>{todo}</li>) }</div>
}