【问题标题】:How can I make useEffect react hook rerender based on a variable value?如何根据变量值使 useEffect 反应钩子重新渲染?
【发布时间】:2020-06-27 18:54:42
【问题描述】:

所以我得到了这个组件:

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 挂钩从数据库中获取所有待办事项,它工作正常。问题是我不知道如何使用useEffect 来触发重新渲染,只要我对 todos 数组进行修改,比如添加、删除或更新。如果我为useEffect 的依赖数组提供todos 变量,我会在控制台中得到一个无限循环日志记录。 如何在 todos 数组更新时使用 useEffect 触发重新渲染?

【问题讨论】:

  • 我认为如果您在 &lt;div&gt; 元素之间添加 {todos.length} 例如,它会首先显示 0 然后重新呈现一次 setTodos 正在更改 todos 状态的值和表示下一个长度。
  • 它不起作用。谢谢。
  • 控制台上是否有任何错误?
  • 你能说明“对 todos 数组进行修改”是什么意思吗?也许问题就在那里,而不是在给出的代码中。
  • 在这种情况下,您需要集中状态。有几种方法可以做到这一点:将状态提升到父组件,使用上下文 API,设置存储管理库(如 Redux)......

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


【解决方案1】:

问题是useEffect里面没有逻辑,看下面这段代码

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

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

这也会产生一个无限循环。但我们总是给出相同的值。问题是当它被更新时,依赖是真的,所以它再次开始执行 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>
    );

【讨论】:

  • 医学博士。 Moshfiqur Ra​​hman Rony,感谢您的回复,但您的解决方案导致了同样的问题。您通过在其范围之外指定一个变量来以这种方式对 useEffect 依赖项撒谎。要将负载用作依赖项,您必须首先在 useEffect 中使用它。
  • useEffect 只会在负载发生变化并且负载变化在您的控制范围内时被调用,因为它永远不需要在 useEffect 内部进行更改。如果您仍然遇到同样的问题,您可以创建一个代码框吗?这是我的代码工作正常
  • 删除、添加、更新时只需改变负载
【解决方案2】:

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

否则,这对于 Redux 来说也是一个很好的应用程序。您将能够使用 Redux fetch 操作来初始化组件,以使用在任何组件上完成的所有 CRUD 操作来填充存储,同时通过修改 reducer 的 API 响应更新存储。然后你可以使用 store 作为 useEffect 依赖来更新组件的本地 todo 状态。

// 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>
}

【讨论】:

    猜你喜欢
    • 2021-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-23
    • 2019-11-23
    相关资源
    最近更新 更多