使用状态更新后防止渲染相机

Prevent Render of Camera After useState update

我有一个设置了叠加模板的相机。一切正常,问题是每次您更改滑块以管理模板的不透明度时,都会导致屏幕完全重新渲染。这会使相机屏幕变黑一两秒钟,然后一切 returns 恢复正常。如果您将滑块移动太多,将导致应用程序完全崩溃。

有谁知道如何在不一直重新渲染的情况下获得所需的效果?这是代码:

import React, { useRef, useState, useEffect, useContext } from "react";
import { Camera } from "expo-camera";
import styled from "styled-components";
import { View, TouchableOpacity, ImageBackground, Image, Dimensions } from 'react-native';
import { Button } from "react-native-paper";
import Slider from '@react-native-community/slider';

import { Text } from "../../components/typography/text.component";

const CameraBackground = styled(View)`
    background-color: #222;
`;

const ImageContainer = styled(View)`
    flex: 1;
    background-color: #000;
`;
      
const SnapButtonContainer = styled(TouchableOpacity)`
    position: absolute;
    z-index: 10000;
    top: 50%;
    margin-top: -40px;
    right: 10px;     
`;

const SnapButton = styled(Button)`
    border: 1px #b22222 solid;
    width: 60px;
    height: 60px;
    background-color: #8b0000;
    border-radius: 50px;
`;

const OpacitySlider = styled(Slider)`
    z-index: 1000;
    width: 400px;
    position: absolute;
    top: 10px;
    left: 50%;
    margin-left: -200px;
`;

export const CameraScreen = ({ route, navigation }) => {
    const cameraRef = useRef();
    const [hasPermission, setHasPermission] = useState(null);
    const [photo, setPhoto] = useState(null);
    const [opacity, setOpacity] = useState(0.5);
    
    const PlaceHolderImageContainer = styled(Image)`
        width: 100%;
        height: 100%;
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        right: 0;
        z-index: 999;
        opacity: ${opacity};
        flex: 1;
    `;

    const CameraContainer = styled(Camera)`
        height: 100%;
        margin: 0 auto;
        width: 100%
    `;
    
    const snap = async () => {
        if (cameraRef) {
            let photoTaken = await cameraRef.current.takePictureAsync();
            setPhoto(photoTaken);
        }
    };

    useEffect(() => {
        (async () => {
            const { status } = await Camera.requestPermissionsAsync();
            setHasPermission(status === 'granted');
        })();
    }, []);

    if (hasPermission === null) {
        return <View />;
    }

    if (hasPermission === false) {
        return <Text>This app does not have access to your camera</Text>
    }

    return (
        <CameraBackground>
            <SnapButtonContainer onPress={snap}>
                <SnapButton  />
            </SnapButtonContainer>
           
            <OpacitySlider
                minimumValue={0}
                maximumValue={1}
                step={0.1}
                minimumTrackTintColor="#FFFFFF"
                maximumTrackTintColor="#000000"
                value={opacity}
                onValueChange={(v) => {setOpacity(v)}}
            />
            <PlaceHolderImageContainer />

            <CameraContainer
                ref={(camera) => (cameraRef.current = camera)}
                type={Camera.Constants.Type.back}
            />
        </CameraBackground>
    );
};

问题是您正在更新主要组件中的状态,这会触发所有其他组件(如相机)的重新渲染,您应该做的是将图像和滑块提取到它们自己的组件中,例如:

const ImageSlider = () => {
  const [opacity, setOpacity] = useState(0.5);

  const PlaceHolderImageContainer = styled(Image)`
        width: 100%;
        height: 100%;
        position: absolute;
        left: 0;
        top: 0;
        bottom: 0;
        right: 0;
        z-index: 999;
        opacity: ${opacity};
        flex: 1;
    `;

  return (
    <>
      <OpacitySlider
        minimumValue={0}
        maximumValue={1}
        step={0.1}
        minimumTrackTintColor="#FFFFFF"
        maximumTrackTintColor="#000000"
        value={opacity}
        onValueChange={(v) => {
          console.log(v);
          setOpacity(v);
        }}
      />

      <PlaceHolderImageContainer
        //source={} //add source here
      />
    </>
  );
};

然后在您自己的组件中使用它,例如:

<CameraBackground>
  //...
  <ImageSlider />
  //...
</CameraBackground>

查看示例小吃:https://snack.expo.dev/SYtePkOAH