Always rendering all the code, changing state!

Asked

Viewed 123 times

1

With this scolding, I start generating this array with the 60 blank positions (initially)

let [list, setList] = useState(Array(60).fill(""))

Then with this array will serve to generate all 60 "buttons" at each pass of the . map(item.,index). as below:

list.map((item, index) => (
     <NumerosParaMarcar index={index} key={index} item={item} />
))

The component: Each button (number)

    const NumerosParaMarcar = (props) => {

    console.log('=== ', props.index)

    return (
        < TouchableOpacity
            delayPressIn={0}
            onPress={() => { marcaNumero(props.index) }}
        >
            <ImageBackground
                style={stylesNumero(props.item).image}
                source={Params.imagemBolaBranca}
            >
                <Text style={stylesNumero(props.item).textNumero}>{(props.index + 1) <= 9 ? "0" + (props.index + 1) : (props.index + 1)}</Text>
            </ImageBackground>
        </TouchableOpacity  >
    )
}

Função Marcanumero

const marcaNumero = (index) => {


    let numero = (index + 1) <= 9 ? "0" + (index + 1) : (index + 1)

    console.log('inicio ', numero)

    //-- REGISTRO O NUMERO MARCADO NA POSIÇÃO DO ARRAY
    let updateArray = list.map((item, itemIndex) => itemIndex === index ? (item == "" ? numero.toString() : "") : item.toString())

    //-- SEPARO SOMENTE OS QUE TEM NUMEROS!
    numerosMarcados = updateArray.filter(numero => numero !== "")

    let num = numerosMarcados.length
    if (num > qtdMaximoMarcar) {
        setQtdMarcadas(num - 1)
        Toast.showWithGravity('Todos os números já foram marcados ', Toast.LONG, Toast.CENTER)
        return;
    }

    atualizaTituloMsgMarcados()

    setNumerosList(numerosMarcados)
    setQtdMarcadas(num)
    setList(updateArray)

    console.log('fim', numerosList)

}

when changing setNumerosList(), you are also running all the code again..

setNumerosList(numerosMarcados)

Main code, where I assemble the components

 return (
    <SafeAreaView style={styles.layout}>

        <View style={[styles.headerRestaMarcar]}>
            <View style={styles.viewtextFaltaMArca} >
                <Text style={stylesTextoRestaMarcar(qtdMarcadas, qtdMaximoMarcar).textoRestaMarcar}>{msgRestaMarcar}</Text>
            </View>
            <BotaoMarcar />
        </View>


        <ScrollView
            contentContainerStyle={{
                alignItems: "center",
                justifyContent: 'center',
                flexDirection: "row",
                flexWrap: 'wrap',
                elevation: 6,
                backgroundColor: '#fff',
                margin: 5,
                borderRadius: 10,
                padding: 5
            }}
        >

            {

                list.map((item, index) => (
                    <NumerosParaMarcar index={index} key={index} item={item} />
                ))
            }

        </ScrollView>

        {qtdMarcadas >= qtdMaximoMarcar && <BotaoSalvarJogada />}

    </SafeAreaView >

);

and it’s beautiful so far, I’ve attached the canvas so you can have an idea,

ps... notice this passage:

<ImageBackground
   style={stylesNumero(props.item).image}
   source={Params.imagemBolaBranca}
 >

i pass the current state of the number inside the array.. to check whether it is filled or not.. if filled in, I change the font color to mark the number clicked by the user.

the logic between checking and unchecking, number of numbers already marked.. etc. is working which is a blz.. apart from the fact that I have to redenrize everything OKK!!

abronca is that it gets too slow, takes about 2 seconds. Hence the user will have to mark 12 numbers, gets very bad... not to mention I created a way of the app, play alone for the user, suggest moves.. It takes 12 seconds to fill everything, due to this unnecessary rendering .

THE BRONCA:

Hence I know that changing an array position causes it to process again, but I need you to only change the state of the given button!

The reason is that when I click on the button (number) I change (fill) the position in the array, and in this state change is that the app runs all the code again, rendering all the buttons from 1 to 60 , according to the array (list), already with the positions filled. this fill, affects the color of the number and the opacity of the image (ball)... I pass the contents of the array position to the Styled, and if this past parameter contains a number (ie) is filled... automatically I change the color of the letter to red for example.

When clicking on some number, I fill in the position of the number i.e., if it was the number 4

["","","","04","","".... 60x]

number 07

["","","","04",""",""07".... 60x]

I tried already useMemo(), useEffect().. I tried to make the individual control of each button, but I still could not solve the problem...

I hope I’ve been clear, thank you!!

inserir a descrição da imagem aqui

Complete code:

import React, { useState, useEffect } from 'react';
import {
    View,
    Text,
    StyleSheet,
    SafeAreaView,
    TouchableOpacity,
    ScrollView,
    ImageBackground,
    Alert
} from 'react-native';

import * as Animatable from 'react-native-animatable';
import Toast from 'react-native-simple-toast';
import { Parse } from 'parse/react-native';
const Params = require('../bin/Parametros')
const Utils = require('../bin/utils')

const MarcarCartelaScreen = ({ navigation }) => {

    const qtdMaximoMarcar = Params.qtdMaximoMarcar
    const qtdNumerosCartela = Params.qtdNumerosCartela

    const [numeroUm, setNumeroUm] = useState("")

    const [msgRestaMarcar, setMsgRestaMarcar] = useState("RESTAM " + qtdMaximoMarcar + " NÚMEROS!");
    const [qtdMarcadas, setQtdMarcadas] = useState(0)

    const [alterouSaldo, setAlterouSaldo] = useState(true)

    let [list, setList] = useState(Array(qtdNumerosCartela).fill(""))
    const [numerosList, setNumerosList] = useState([])
    let numerosMarcados = []

    //alterouSaldo && Utils.atualizaSaldoUsuario(navigation)

    const zeraMarcacoes = () => {
        setList(Array(qtdNumerosCartela).fill(""))
        setQtdMarcadas(0)
        atualizaTituloMsgMarcados();
    }

    const salvarJogada = async () => {

        let saldoAtaual = Params.saldoUsuarioDecimal - Params.valorJogada
        if (saldoAtaual < 0) {
            Alert.alert('Atenção!', 'Saldo insuficiente para registrar esta jogada, faça uma recarga e concorra. ', [{ text: 'Ok' }]);
            return;
        }

        const myNewObject = new Parse.Object('jogos');
        myNewObject.set('jogo', numerosList);
        myNewObject.set('usuario', Parse.User.current());

        const usuario = JSON.parse(JSON.stringify(Parse.User.current()));
        let User = new Parse.Object('_User');
        User.set('objectId', usuario.objectId);
        User.set('saldo', saldoAtaual);

        try {

            await myNewObject.save();
            await User.save();

            Toast.showWithGravity('Sua jogada foi registrada. Boa sorte! ', Toast.LONG, Toast.CENTER);

            zeraMarcacoes()

            Params.saldoUsuarioDecimal = saldoAtaual
            setAlterouSaldo(true)

        } catch (error) {
            console.log(error)
            Toast.showWithGravity('Algum erro ocorreu, tente mais tarde! ', Toast.LONG, Toast.CENTER);
            return;
        }

    }

    const atualizaTituloMsgMarcados = () => {

        // console.log('---', numerosMarcados.length)
        let restam = qtdMaximoMarcar - numerosMarcados.length
        // console.log('resta ---', restam)

        let msg = restam > 1 && "RESTAM " + restam + " NÚMEROS!"
        msg = restam == 1 ? "RESTA 1 NÚMERO" : msg
        msg = restam == 0 ? numerosMarcados.toString().split(",").join(" ") : msg
        setMsgRestaMarcar(msg)

    }

    const marcarAleatorio = () => {

        setTimeout(function () {

            let num = Math.floor(Math.random() * qtdNumerosCartela + 1)
            let numero = (num) <= 9 ? "0" + num : num

            let index = num - 1;
            if (numerosMarcados.indexOf(numero) > 0) {
                marcarAleatorio()
                return;
            }

            let updateArray = list.map((item, itemIndex) => itemIndex === index ? (item == "" ? numero.toString() : "") : item.toString())

            //-- SEPARO SOMENTE OS QUE TEM NUMEROS!
            numerosMarcados = updateArray.filter(numero => numero !== "")
            list[index] = numero

            setNumerosList(numerosMarcados)
            atualizaTituloMsgMarcados()

            if (numerosMarcados.length < qtdMaximoMarcar) {
                marcarAleatorio()
            } else {
                setNumerosList(numerosMarcados)
                setQtdMarcadas(numerosMarcados.length)
            }

        }, 0);

    }

    const marcaNumero = (index) => {


        let numero = (index + 1) <= 9 ? "0" + (index + 1) : (index + 1)

        console.log('inicio ', numero)

        //-- REGISTRO O NUMERO MARCADO NA POSIÇÃO DO ARRAY
        let updateArray = list.map((item, itemIndex) => itemIndex === index ? (item == "" ? numero.toString() : "") : item.toString())

        //-- SEPARO SOMENTE OS QUE TEM NUMEROS!
        numerosMarcados = updateArray.filter(numero => numero !== "")

        let num = numerosMarcados.length
        if (num > qtdMaximoMarcar) {
            setQtdMarcadas(num - 1)
            Toast.showWithGravity('Todos os números já foram marcados ', Toast.LONG, Toast.CENTER)
            return;
        }

        atualizaTituloMsgMarcados()

        setNumerosList(numerosMarcados)
        setQtdMarcadas(num)
        setList(updateArray)

        console.log('fim', numerosList)

    }

    const marcarCartela = () => {
        marcarAleatorio()
    }

    // useEffect(() => {
    //     //alterouSaldo && Utils.atualizaSaldoUsuario(navigation)
    //     console.log('uese effect alterasaldo')

    // }, [alterouSaldo]);



    const NumerosParaMarcar = (props) => {

        console.log('=== ', props.index)

        return (
            < TouchableOpacity
                delayPressIn={0}
                onPress={() => { marcaNumero(props.index) }}
            >
                <ImageBackground
                    style={stylesNumero(props.item).image}
                    source={Params.imagemBolaBranca}
                >
                    <Text style={stylesNumero(props.item).textNumero}>{(props.index + 1) <= 9 ? "0" + (props.index + 1) : (props.index + 1)}</Text>
                </ImageBackground>
            </TouchableOpacity  >
        )
    }

    const BotaoSalvarJogada = () => {
        return (
            <Animatable.View
                style={styles.footer}
                animation="bounceIn">
                <TouchableOpacity
                    style={styles.btSalvarJogada}
                    onPress={() => { salvarJogada() }}
                >
                    <Text style={styles.textBtSalvarJogada}>SALVAR JOGADA</Text>
                </TouchableOpacity>
            </Animatable.View>
        )
    }

    const BotaoMarcar = () => {

        return (

            <Animatable.View
                style={styles.viewbtMarcar}
                animation="tada">

                <TouchableOpacity
                    style={styles.btMarcar}
                    onPress={() => { marcarCartela() }}>

                    <Animatable.Text animation="pulse" easing="ease-out" iterationCount="infinite"
                        style={{
                            alignContent: "center",
                            justifyContent: "center",
                            fontSize: 55,
                            textAlign: 'center'
                        }}></Animatable.Text>
                </TouchableOpacity>

            </Animatable.View>
        )
    }

    useEffect(() => {
        //!mostraBtMarcar && setMostraBtMarcar(true);
        console.log('GERAL - MARCAR CATERLA')

    }, []);

    return (
        <SafeAreaView style={styles.layout}>

            <View style={[styles.headerRestaMarcar]}>
                <View style={styles.viewtextFaltaMArca} >
                    <Text style={stylesTextoRestaMarcar(qtdMarcadas, qtdMaximoMarcar).textoRestaMarcar}>{msgRestaMarcar}</Text>
                </View>
                <BotaoMarcar />
            </View>


            <ScrollView
                contentContainerStyle={{
                    alignItems: "center",
                    justifyContent: 'center',
                    flexDirection: "row",
                    flexWrap: 'wrap',
                    elevation: 6,
                    backgroundColor: '#fff',
                    margin: 5,
                    borderRadius: 10,
                    padding: 5
                }}
            >

                {

                    list.map((item, index) => (
                        <NumerosParaMarcar index={index} key={index} item={item} />
                    ))
                }

            </ScrollView>

            {qtdMarcadas >= qtdMaximoMarcar && <BotaoSalvarJogada />}

        </SafeAreaView >

    );
};

// export default React.memo(MarcarCartelaScreen);
export default MarcarCartelaScreen;

const stylesTextoRestaMarcar = (qtdM, qtdMaximoMarcar) => StyleSheet.create({
    textoRestaMarcar: {
        marginTop: 6,
        opacity: qtdM >= qtdMaximoMarcar ? 0.8 : 0.7,
        fontSize: 25,
        color: qtdM >= qtdMaximoMarcar ? "#FFF" : "#FFF",
        textAlign: qtdM >= qtdMaximoMarcar ? "center" : "left",
        fontFamily: 'Caramel Sweets',
    },
})

const stylesNumero = (item) => StyleSheet.create({

    textNumero: {
        fontSize: 18,
        // marginTop: 13,
        marginTop: item === "" ? 13 : 10,
        fontFamily: 'Caramel Sweets',
        color: item !== "" ? "#ff8080" : "#05375a",
        fontFamily: item === "" ? 'Caramel Sweets' : null,
        // opacity: item !== "" ? 1 : 0.8,

    },
    // textNumero: {
    //     fontSize: item !== "" ? 21 : 18,
    //     marginTop: item !== "" ? 13 : 10,
    //     fontFamily: item !== "" ? 'Caramel Sweets' : null,
    //     color: item !== "" ? "#ff8080" : "#05375a",
    //     opacity: item !== "" ? 1 : 0.8,

    // },

    image: {
        alignItems: 'center',
        width: 45,
        height: 45,
        backgroundColor: "#FFF",
        opacity: item !== "" ? 0.6 : 0.8,
        // background: item ? `url(${bolaBranca})` : `url(${bolaMarcada})`,
    }

});

const styles = StyleSheet.create({

    layout: {
        alignItems: "center",
        flex: 1,
        elevation: 10,
    },

    header: {
        width: "100%",
        // backgroundColor: '#FF8C00', //Params.corPrimary,
        justifyContent: 'center',
        padding: 10,
        height: 60,
        flexDirection: "row",
    },
    headerRestaMarcar: {
        elevation: 6,
        margin: 4,
        backgroundColor: "#314968",
        paddingLeft: 10,
        height: 60,
        width: "98%",
        // marginBottom: 20,
        flexDirection: "row",
        borderRadius: 5,
    },

    textoHeader: {
        color: '#CCC',
        fontSize: 17,
        textAlign: "center",
    },
    footer: {
        width: '100%',
        justifyContent: 'center',
        alignItems: 'center',
        position: 'absolute', //Here is the trick
        bottom: 20,
    },
    btSalvarJogada: {
        elevation: 6,
        width: '70%',
        height: 70,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: "#FF9800",
        borderRadius: 25,
        borderColor: '#05375a',
        borderWidth: 4,
        opacity: 0.9
    },
    textBtSalvarJogada: {
        marginTop: 10,
        color: '#05375a',
        fontSize: 30,
        fontFamily: 'Caramel Sweets'
    },

    viewtextFaltaMArca: {
        flex: 1,
        alignSelf: "center",
    },

    viewMsgTitulo: {
        alignSelf: "center",
        // backgroundColor:"red"
    },

    viewbtFecharHead: {
        flex: 1,
        alignSelf: "center",
        alignContent: "flex-end",
        alignItems: "flex-end"
    },

    viewbtMarcar: {
        alignSelf: "center",
        // backgroundColor: "#FFF000",
        width: 70,
        height: 70,
        marginRight: 5
    },
    btMarcar: {
        alignContent: "center",
        alignSelf: "center",
        alignItems: 'center',
    },

});

New code...

import React from 'react';
import { View } from 'react-native';
import styled from 'styled-components/native'

const ButtonDefault = styled.Text`
    color: ${props => props.status ? '#ff8080' : '#05375a'}
    margin-top: 13px;
    fontFamily: 'Caramel Sweets';
    font-size: 18px;
`;

const Button = React.memo((props) =>
    <>
        {console.log("===", props.index)}

        <ButtonDefault {...props} />
    </>
);

const MarcarCartelaScreen = () => {

    console.log('Rodando pagina');

    const [list, setList] = React.useState(Array(60).fill(false))

    const handleOnClick = React.useCallback((index) => {

        console.log("---------------------------cliquei ", index);

        let item = [...list];
        item[index] = !item[index];
        setList(item);

    }, [list]);

    return (

        <View>

            {
                list.map((i, x) =>
                    <Button
                        // onClick={e => handleOnClick(e, x)}
                        onPress={e => handleOnClick(x)}
                        status={i}
                        index={x}
                        key={x}>
                        {(x + 1)}
                    </Button>
                )}

        </View>

    )


};

export default MarcarCartelaScreen;

inserir a descrição da imagem aqui

  • 1

    It even happens that you described because it is reactive from any update it re-mounts the component and performs all functions. One way is using useCallback and memo to decrease and also generate the array of items outside think it improves. You have to assemble in asking a minimal example missing the components to give a better explanation

  • 1

    I would use an array object I think would look better and the button has to put the code

  • Everybody, I’ll edit the question to try to improve...

  • I don’t know if I made my situation worse :D was worth!! I modified it.

  • 2

    How’s the function code marcaNumero ?

  • 1

    In addition to the code of marcaNumero, as Isac said, where does this function come from? Also show the parent code of the NumerosParaMarcar.

  • 1

    the problem must be in logic the markNumer I made an example and I did not have rendering as you showed in the figure.

  • I thought about it now, I did not put the Marcanumero... I’m going for now!! , has how to show me and example @novic

  • I added the main component assembly code!! Obg!!!

  • your code is totally weird, where you can get list inside a component that marks? I believe that is the problem, I created an answer and does not have this problem, but, it is hidden and its code can not reproduce

  • @novic hello, well.. my idea should be this and so I did... the list is initially created with the 60 blank positions, and with each click on the number, I go there in the list and fill the position of the number, 35 in the 35 position (in case 36, because it starts at the correct zero?... ) every number clicked I go there in position and fill. this fill modification is ta making it process all the code again.... I will put the complete code!!!

  • help me @novic :( I added the full code

  • 1

    I made the code down there, if you don’t take it negative you can check it out.

  • Masssa.. I go from a balcony here and do some testing, bro thanks!!! Jump back here!!! Thanks

  • @novic Hello .. do you believe that after some work in adapting to the reac-Active, and after running continues running all the code?? I was pasmo man kkk... but it really got a little more performatic, but if I didn’t perform

  • is something you’re still missing.

  • I can’t imagine! if you need more information here, obg! that version I posted here, was practically yours.

Show 13 more comments

1 answer

-1

I’m realizing that wrote more than needed, I decided to create a minimal example demonstrating the rendering only of the clicked component, with useCallback and memo which checks fairly if the value has actually been changed:

const ButtonDefault = window.styled.button`
  width: 30px;
  height: 30px;
  border-radius: 50%;
  margin: 4px;
  background-color: ${props => props.status ? 'yellow' : '#efefef'}
`;

const Button = React.memo((props) => <ButtonDefault {...props}/>);

function App() {
  console.log('clicou');
  const [list, setList] = React.useState(Array(60).fill(false))
  const handleOnClick = React.useCallback((e, index) => {
    let item = [...list];
    item[index] = !item[index];
    setList(item);
  }, [list]);
  return (
    <div>
    <div>
    { list.map((i,x) => 
       <Button onClick={e => handleOnClick(e, x)}
          status={i} key={x}>{(x + 1)}</Button>
      )
    }
    </div>
    <hr />
    <div>Quantidade de selecionados: {list.filter(x => x === true).length}</div>
    </div>
  )
}

ReactDOM.render( <App/> , document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script><script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script><script src="https://unpkg.com/react-is/umd/react-is.production.min.js"></script><script src="https://unpkg.com/styled-components/dist/styled-components.min.js"></script>
<div id="root">Carregando ...</div>

With each click on the button only it is changed, and this denotes performance in component rendering, not having those famous crashes reported in question.

  • Explanations for another negative vote

  • tbm do not know pq... until pq solved for the web environment.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.