【问题标题】:React setState of useState hook successfully updating state, but not re-rendering component反应useState钩子的setState成功更新状态,但不重新渲染组件
【发布时间】:2020-03-31 16:54:38
【问题描述】:

我正在尝试更新我的旧 Todo List React 应用程序,以便它使用钩子,但我一辈子都无法解决这个问题。 setTodos 已成功更新加载时的状态,如 React 开发人员工具中所示,但组件不会重新渲染,并且屏幕上会显示一个空白的待办事项列表。只有当我将一个待办事项添加到列表中时,它才会重新渲染并且所有待办事项都会显示出来。这是我得到的:

const App = () => {

// Todos are the only state in App
const [ todos, setTodos ] = useState([]);

// Fetches Todos from Firestore database on load
useEffect(() => {
    const initialState = [];
    dbTodos.get().then((snapshot) => {
        snapshot.forEach((doc) => {
            const currentTodo = doc.data();
            currentTodo['id'] = doc.id;
            initialState.push(currentTodo);
        });
    });
    setTodos(initialState);
    // eslint-disable-next-line
}, []);

// Add Todo
const addTodo = (title) => {
    const newTodo = {
        title     : title,
        completed : false
    };
    dbTodos.add(newTodo).then((doc) => {
        newTodo['id'] = doc.id;
        setTodos([ ...todos, newTodo ]);
    });
};

这是我在实现钩子之前使用的代码:

componentDidMount() {
    dbTodos.get().then((snapshot) => {
        snapshot.forEach((doc) => {
            const currentTodo = doc.data();
            currentTodo['id'] = doc.id;
            setState({ ...state, todos: [ ...state.todos, currentTodo ] });
        });
    });
};

【问题讨论】:

  • 请添加JSX的代码或者你渲染的任何地方

标签: reactjs react-hooks


【解决方案1】:

你应该在UseEffect中移动你的setTodos

useEffect(() => {
    dbTodos.get().then((snapshot) => {
        const initialState = [];    // Also this you can move here

        snapshot.forEach((doc) => {
            const currentTodo = doc.data();
            currentTodo['id'] = doc.id;
            initialState.push(currentTodo);
        });

        setTodos(initialState);   /// here
    });
}, []);

【讨论】:

  • 哇,这就像一个魅力。你能解释一下这个解决方案背后的逻辑,以及为什么我的代码不起作用?
  • 因为 dbTodos.get().then 被称为异步,这意味着在您的解决方案中,订单调用是 1. 准备空数组 (initialState) 2. 使用来自 initialState 3 的数组设置 todos。 dbTodos .get finished 将项目添加到数组中(initialState)
  • 啊,我明白了。有趣的部分是状态 did 包含它在加载时获取的所有内容,它们只是没有被渲染。似乎我的代码根本不应该改变状态
  • @JimmyD 是的,但 initialState 在 setTodos 之后更新,这意味着反应没有捕捉到状态变化,想象它就像这个 initialState 只是内存中的引用,并且该引用被 setTodos 设置为新的 todos 和该回调仍然可以访问该内存,这就是它仍然可以更新的原因,但是当该变量更改时现在调用 setTodos 时会重新渲染
  • 好吧,这更有意义。真的很感谢帮助的人
【解决方案2】:

当您在 useEffect 中设置状态时,您必须在依赖项中添加 setState。 不要这样做,而是使用另一个箭头函数并从 useEffect 调用它。

使用下面的代码

const App = () => {

// Todos are the only state in App
const [ todos, setTodos ] = useState([]);

// Fetches Todos from Firestore database on load
const fetchData = () => {
    const initialState = [];
    dbTodos.get().then((snapshot) => {
        snapshot.forEach((doc) => {
            const currentTodo = doc.data();
            currentTodo['id'] = doc.id;
            initialState.push(currentTodo);
        });
    });
    setTodos(initialState);
}

useEffect(() => {
  fetchData();
}, []);

// Add Todo
const addTodo = (title) => {
    const newTodo = {
        title     : title,
        completed : false
    };
    dbTodos.add(newTodo).then((doc) => {
        newTodo['id'] = doc.id;
        setTodos([ ...todos, newTodo ]);
    });
};

【讨论】:

    【解决方案3】:

    在 useEffect 中创建空数组。发出请求。将空数组设置为状态。当请求得到满足时,您通过 ref 在数组中进行更改。因此,您在开发工具中看到您的数组并且反应不会重新渲染您的组件。

    const App = () => {
    
    // Todos are the only state in App
    const [ todos, setTodos ] = useState([]);
    
    // Fetches Todos from Firestore database on load
    useEffect(() => {
        dbTodos.get().then((snapshot) => {
            setTodos(snapshot.map((doc) => ({
              id: doc.id,
              ...doc.data(),
            })));
        });
    }, []);
    
    // Add Todo
    const addTodo = (title) => {
        const newTodo = {
            title     : title,
            completed : false
        };
        dbTodos.add(newTodo).then((doc) => {
            newTodo['id'] = doc.id;
            setTodos([ ...todos, newTodo ]);
        });
    };

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-05
      • 2019-10-06
      • 2018-02-27
      • 2020-04-19
      • 1970-01-01
      • 2023-03-25
      相关资源
      最近更新 更多