skip to Main Content

i am using react native and creating a chat app. Now i have few messages objects in array and i’m rendering them in flatlist now when i type message and click on send. my typed message gets clear after adding the message in array of messages. but message does not add on screen with rest of messages. as it seems like component is not rerendering cause when i click on send , message disappear from string but in array of list there that message added succesfully with rest of messages

Now, Can you please tell me whats wrong here in code ?

const ChatComponent = (props) => {
  const [message, setMessage] = useState('');
  const [messages, setMessages] = useState([
    { id: '1', text: 'Hello, how are you?', sender: 'John' },
    { id: '2', text: 'Im good, thanks for asking!', sender: 'Jane' },
    { id: '3', text: 'What have you been up to?', sender: 'John' },
    { id: '4', text: 'Not much, just working and taking care of some errands.', sender: 'Jane' },
  ]);

  const listRef = useRef(null);

  useEffect(() => {
    setMessages(messages);
  }, [messages]);

  const handleSend = () => {
    LayoutAnimation.configureNext({
        duration: 500,
        update: {
          type: LayoutAnimation.Types.easeInEaseOut,
        },
      }, () => {
        setMessages([...messages, { id: messages.length + 1, text: message, sender: 'Me' }]);
        setMessage('');
      });
  };

  return (
    <SafeAreaView style={styles.container}>
      <FlatList
        ref={listRef}
        data={messages}
        renderItem={({ item }) => (
          <View style={[styles.messageContainer, item.sender === 'Me' && styles.me]}>
            <Text style={[styles.sender, item.sender === 'Me' && styles.me]}>{item.sender}:</Text>
            <Text style={[styles.message, item.sender === 'Me' && styles.me]}>{item.text}</Text>
          </View>
        )}
        keyExtractor={item => item.id}
      />
      <View style={styles.inputContainer}>
        <TextInput
          style={styles.input}
          placeholder="Type a message..."
          value={message}
          onChangeText={text => setMessage(text)}
        />
        <TouchableOpacity style={styles.button} onPress={handleSend}>
          <Text style={styles.buttonText}>Send</Text>
        </TouchableOpacity>
      </View>
    </SafeAreaView>
  );
};

3

Answers


  1. remove the useEffect.

    It will re-render the component infinitely since you are setting the same useState included in the dependency array

    //remove this
    useEffect(() => {
        setMessages(messages);
      }, [messages]);
    
    Login or Signup to reply.
  2. You need to remove this setFunction setMessage(''); because react uses queue, that mean the messages state will get the last state value.

    Login or Signup to reply.
  3. Updating code inside the LayoutAnimation callback not synchronize with React UI rendering.

    Remove layout animation code inside button press event handler and delegate it to useEffect as below :

     useEffect(()=>{
          LayoutAnimation.configureNext({
            duration: 500,
            update: {
              type: LayoutAnimation.Types.easeInEaseOut,
            },
          });
    
      },[messages.length])
    
      const handleSend = () => {
          setMessages([...messages, { id: messages.length + 1, text: message, sender: 'Me' }]);
          setMessage('');
      };
    
    

    You will both maintain layout animation and state updates.

    Working Demo – https://snack.expo.dev/@emmbyiringiro/ea7d26

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search