useState挂钩总是落后1步

时间:2019-12-17 22:44:57

标签: reactjs

我看到了其他标题完全相同的问题,但没有一个解决我的问题: 这是我的代码:

import React, { useState } from 'react';
import Validation from './Validation/Validation';
import Char from './Char/Char';

function App() {
  const [textState, textSetState] = useState('');
  const [charsState, charsSetState] = useState([]);

  let inputChange = (event) => {
    textSetState(event.target.value);
    charsSetState(event.target.value.split('').map((char, index) => {
      return <Char char={char} key={index} click={() => { deleteCharHandler(index) }} />
    }));
  }

  const deleteCharHandler = (index) => {
    alert(textState);
  }
  return (
    <div className="App">
      <input type="text" onChange={(event) => inputChange(event)} />
      <Validation text={textState} />
      {charsState}
    </div>
  );
}

export default App;

这是结果:

enter image description here

当我单击一个字符时,它会从后面的1步中显示值,就像上面的示例一样。

4 个答案:

答案 0 :(得分:3)

您要在状态中放置一组呈现的Char组件,然后进行呈现。这种方法存在很多问题。

  1. 状态(charsState)的本地副本不会立即更新;相反,React将使用新的state值重新渲染组件。
  2. 由于您正在函数中定义onClick回调,因此deleteCharHandler将始终引用状态的过时副本。
  3. 以这种方式在锁步中更新多个状态挂钩将导致发生其他重新渲染。

由于示例中的命名有点令人困惑,因此很难说出所需的行为是什么,以便为如何解决或重构提供良好的建议。

答案 1 :(得分:2)

所以有些事情可能会或可能不会引起问题,所以让我们先清除一下几件事:

  1. 您不需要在输入中传递匿名函数:

    <input type="text" onChange={inputChange} />应该足够

  2. 与OG状态一样,同时调用两个setState绝不是一个好主意,因此让我们将两者结合起来:

    const [state, setState] = useState({text: '', char: []});

更新完所有内容后,您应该将一个状态对象设置为onClick。

  1. 您的Char对象使用的是click而不是onClick?除非您将其用作回调方法,否则我将切换至:

    return <Char char={char} key={index} OnClick={() => deleteCharHandler(index)} />

如果最后还是不能解决问题,您只需传递deleteCharHandler更新的文本值,而不用重新获取状态值

答案 2 :(得分:1)

我认为您需要useCallback或在参数中传递textState。 deleteCharHandler方法的时间不会随textState值的变化而改变。

尝试:

return <Char char={char} key={index} click={() => { deleteCharHandler(index, textState) }} />
...

const deleteCharHandler = (index, textState) => {
    alert(textState);
  }

或:

import React, { useState, useCallback } from 'react';
...
const deleteCharHandler = useCallback(
  (index) => {
    alert(textState);
  }, [textState]);

答案 3 :(得分:1)

尝试一下

function App() {
    const [textState, textSetState] = useState('');

    const inputChange = useCallback((event) => {
        textSetState(event.target.value);
    },[])

    function renderChars(){
        return textState.split('').map((char, index) => {
            return <Char char={char} key={index} click={() => { deleteCharHandler(index) }} />
        }));
    }

    const deleteCharHandler = useCallback( (index) => {
         alert(textState);
    }, [textState])

    return (
        <div className="App">
            <input type="text" onChange={inputChange} />
            <Validation text={textState} />
           {renderChars()}
       </div>
   );
}