简体   繁体   中英

Component in React Native wrongly rendered after state update

I'm having a really weird problem with my React Native component. Component's state is correctly updated, but it is not reflected on what is rendered by the component.

Here is what my component looks like (I didn't include imports and other parts of the code that are irrelevant):

export default function MessageActionsModal({ 
  message,
  actions,
  onClose
}) {
  const [dimensions, setDimensions] = useState(null);
  const [messageActions, setMessageActions] = useState([]);

  useEffect(() => {
    if (message !== null) {
      setMessageActions(actions.map((a) => ({
        ...a,
        onPress: () => {
          a.onPress(message?.item);
          onClose();
        }
      })))
    } else {
      setMessageActions([]);
    }
  }, [message, actions, onClose]);
  
  if (message === null) {
    return null;
  }

  return (
    <Portal>
      <TouchableOpacity
        style={styles.messageActionsModal}
        activeOpacity={0}
        onPress={onClose}
      >
        <Portal style={styles.messageActionsModalInnerContainer}>
          <MessageListItem
            style={[
              styles.message,
              getMessagePositionAndDimensions(message)
            ]}
            {...message.item}
          />
          <View
            style={[
              styles.messageActionsMenu,
              getMenuPosition(dimensions, message)
            ]}
            {...dimensions === null && {
              onLayout: ({ nativeEvent }) => setDimensions({
                width: nativeEvent.layout.width,
                height: nativeEvent.layout.height
              })
            }}
          >
            <Text>{'LEN'}{messageActions.length}</Text>
            <Text>{'LOG'}{console.log(messageActions.length)}</Text>

            {messageActions.map((a) => (
              <Button
                key={a.title}
                style={styles.messageActionButton}
                title={a.title}
                variant="text"
                startIcon={a.icon}
                startIconProps={{
                  style: styles.messageActionButtonIconWrapper,
                  iconStyle: styles.messageActionButtonIcon,
                  fill: Colors.yellow
                }}
                onPress={a.onPress}
              />
            ))}
          </View>
        </Portal>
      </TouchableOpacity>
    </Portal>
  );
}

So basically, after messageActions are updated in the useEffect , component renders incorrectly and neither message action is rendered (although one item should be rendered).

Another interesting thing is that the following code renders "LEN 0", but it logs "LOG 1" in the console.

<Text>{'LEN'}{messageActions.length}</Text>
<Text>{'LOG'}{console.log(messageActions.length)}</Text>

What am I doing wrong here?

You can try memoizing actions instead of using useEffect . Here's an example:

const messageActions = useMemo(() => {
    if (message === null) {
      return [];
    }
    
    return actions.map((a) => ({
        ...a,
        onPress: () => {
          a.onPress(message?.item);
          onClose();
        }
      }));
}, [message, actions, onClose]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM