Q:

React useState lagging by one keystroke

Okay - I'm having an issue with my react app onChange attribute lagging by one keystroke.
I am pretty sure this has to do with this code block running before the state is being updated. 
if (hex.length === 3) {
      let newColor = hex.join('');
      let newColors = [...colors, newColor];
      setColors(newColors);
      setHex([]);
    }

I tried moving the above block to a useEffect hook (as such) so that it would run when the value of hex changes to remedy this.
useEffect(() => {
if (hex.length === 3) {
      let newColor = hex.join('');
      let newColors = [...colors, newColor];
      setColors(newColors);
      setHex([]);
    }
}, hex)

This did not work as expected, and I'm still facing the same issue. The goal is when an input is received, if the length of the total ASCII input is 3 characters or more, it will convert that text ([61, 61, 61] for example) into hex string of 6 characters, which will eventually be converted into a color hex code.
All of my code is as follows. 
import TextInput from './components/TextInput';
import Swatch from './components/Swatch';
import './App.css';

function App() {
  const [colors, setColors] = useState([]);
  const [hex, setHex] = useState([]);
  const [text, setText] = useState();

  const convertToHex = (e) => {
    const inputText = e.target.value;
    setText(inputText);
    for (let n = 0, l = inputText.length; n < l; n++) {
      let newHex = Number(inputText.charCodeAt(n)).toString(16);
      let newHexArr = [...hex, newHex];
      setHex(newHexArr);
    }
    if (hex.length === 3) {
      let newColor = hex.join('');
      let newColors = [...colors, newColor];
      setColors(newColors);
      setHex([]);
    }
  };

  return (
    <div className='App'>
      <h1 id='title'>Color Palette Generator</h1>
      <TextInput func={convertToHex} />
      <Swatch color='#55444' />
    </div>
  );
}

export default App;

A:

How is the TextInput component managing its state (the input's value)?
I suspect you might have a problem there, as changing that TextInput component with a simple controlled input:
<input type="text" onChange={ handleOnChange } value={ text } />

And using your existing code as handleOnChange works as expected:

const App = () => {
  const [colors, setColors] = React.useState([]);
  const [hex, setHex] = React.useState([]);
  const [text, setText] = React.useState('');

  const handleOnChange = (e) => {
    const inputText = e.target.value;
    
    // I thought your problem was related to `text`...:
    setText(inputText);
    
    for (let n = 0, l = inputText.length; n < l; n++) {
      let newHex = Number(inputText.charCodeAt(n)).toString(16);
      let newHexArr = [...hex, newHex];
      setHex(newHexArr);
    }
    
    if (hex.length === 3) {
      // But looking at the comments it looks like it's related to `colors`, so as
      // pointed out already you should be using the functional version of `setState`
      // to make sure you are using the most recent value of `colors` when updating
      // them here:
      setColors(prevColors => [...prevColors, hex.join('')]);
      setHex([]);
    }
  };

  return (
    <div className="app">
      <h1 className="title">Color Palette Generator</h1>
      <input className="input" type="text" onChange={ handleOnChange } value={ text } />
      <pre>{ hex.join('') }</pre>
      <pre>{ colors.join(', ') }</pre>
    </div>
  );
}

ReactDOM.render(<App />, document.querySelector('#app'));
body {
  font-family: monospace;
  margin: 0;
}

.app {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 100vh;
}

.title {
  display: flex;
  margin: 32px 0;
}

.input {
  margin: 0 4px;
  padding: 8px;
  border: 2px solid black;
  background: transparent;
  border-radius: 2px;
}

.as-console-wrapper {
  max-height: 45px !important;
}
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>

In any case, there are a few other things that could be improved on that code, such as using a single useState, using useCallback, adding a separate <button> to push colors to the state or actually doing the RGB to HEX conversion:

const App = () => {
  const [state, setState] = React.useState({
    value: '',
    hex: '',
    colors: [],
  });
  
  const handleInputChange = React.useCallback((e) => {
    const nextValue = e.target.value || '';  
    const nextHex = nextValue
      .trim()
      .replace(/[^0-9,]/g, '')
      .split(',')
      .map(x => `0${ parseInt(x).toString(16) }`.slice(-2))
      .join('')
      .toUpperCase();

    setState((prevState) => ({
      value: nextValue,
      hex: nextHex,
      colors: prevState.colors,
    }));
  }, []);
  
  const handleButtonClick = React.useCallback(() => {
    setState((prevState) => {
      return prevState.hex.length === 3 || prevState.hex.length === 6 ? {
        value: '',
        hex: '',
        colors: [...prevState.colors, prevState.hex],
      } : prevState;
    });
  }, []);

  return (
    <div className="app">
      <h1 className="title">Color Palette Generator</h1>
      
      <input
        type="text" 
        className="input"
        value={ state.value } 
        onChange={ handleInputChange } />
      
      <input
        type="text" 
        className="input"
        value={ `#${ state.hex }` }
        readOnly />
      
      <button className="button" onClick={ handleButtonClick }>
        Add color
      </button>
      
      <pre className="input">{ state.colors.join('\n') }</pre>
    </div>
  );
}

ReactDOM.render(<App />, document.querySelector('#app'));
body {
  font-family: monospace;
  margin: 0;
}

.app {
  display: flex;
  flex-direction: column;
  align-items: center;
  min-height: 100vh;
}

.title {
  display: flex;
  margin: 32px 0;
}

.input,
.button {
  margin: 8px 0 0;
  padding: 8px;
  border: 2px solid black;
  background: transparent;
  border-radius: 2px;
  width: 50vw;
  box-sizing: border-box;
}

.button {
  cursor: pointer;
}
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>

<div id="app"></div>

