skip to Main Content

This is for an interactive bible.

In the following code I have buttons that are being conditionally rendered based upon the buttons I previously clicked.

The code calls an API to retrieve the data.

useEffect(() => {
        dispatch(fetchBibleBooks());
        }, [dispatch]);

    useEffect(() => {
        if(selectedBook && chapter){
            dispatch(fetchBibleBookChapter( {selectedBook, chapter} ));
        }
    }, [dispatch, selectedBook, chapter]);

    useEffect(() => {
        setOTBooks(bibleArray.filter(book => book.testament === 'OT'));
    }, [ clickedOT ]);

    useEffect(() => {
        setNTBooks(bibleArray.filter(book => book.testament === 'NT'));        
    }, [ clickedNT ]);  

    useEffect(() => {
        setBookChapters(bibleArray.find(book => book.id === selectedBook)?.chapters || []);
    }, [ selectedBook ]);

    useEffect(() => { 
       bibleArray.filter(chapter => chapter);
       const subsetBibleArray = bibleArray.map( text => text.cleanText ); 
       setChapterText(subsetBibleArray);
       
    });

    return(
        <Container>
            <Row>
                <Col style={{textAlign: 'center'}}>
                    <h1 style={{ color: 'darkblue'}}>Biblia Interactiva</h1>
                    <Button style={{margin: '2rem'}} color='warning' size='lg' onClick={() => setClickedOT(true)}>
                        Antiguo Testamento
                    </Button>{' '}
                    <Button style={{margin: '2rem'}} color='warning' size='lg' onClick={() => setClickedNT(true)}>
                        Nuevo Testamento
                    </Button>
                </Col>
            </Row>
            <Row style={{marginTop:'4rem'}}>
                <Col style={{textAlign:'left', marginLeft:'-18rem'}}>
                    {
                         clickedOT && otBooks.sort((b1, b2) => {
                                    if (b1.order < b2.order) return -1;
                                    if (b1.order > b2.order) return 1;
                                    return 0;
                                }).map(book => (
                                    <Button color='primary' key={book.order} style={{ margin: '4px' }} onClick={() => setSelectedBook(book.id)}>
                                        {book.name}
                                    </Button> 
                            ))
                        }
                </Col>
                <Col style={{textAlign:'left', marginRight:'-18rem'}}>
                    {
                        clickedNT && ntBooks.sort((b1, b2) => {
                                    if (b1.order < b2.order) return -1;
                                    if (b1.order > b2.order) return 1;
                                    return 0;
                                }).map(book => (
                                    <Button color='primary' key={book.order} style={{ margin: '4px' }} onClick={() => setSelectedBook(book.id)}>
                                        {book.name}
                                    </Button>
                            ))}
                </Col>
            </Row>
            <Row>
                <Col style={{textAlign:'center', marginLeft:'', marginTop: '6rem'}}>
                        {
                            bookChapters.map(ch => (
                                    <Button color='success' key={ch.id} style={{ margin: '4px' }} onClick={() => setChapter(ch.chapter)}>
                                        {ch.chapter}
                                    </Button>
                                )
                            )
                        }
                </Col>
            </Row>
            <Row>
                <Col style={{textAlign:'left', marginLeft:'', marginTop: '6rem'}}>
                        {
                            chapterText.map((text, idx) => (
                                    <p key={idx}>
                                        {text}
                                    </p>
                                )
                            )
                        }
                </Col>
            </Row>
        </Container>
    )
}

The code work well the first go around but if I re-click one of the Bible book buttons, the previously rendered chapter buttons will disappear and so will the text, which is fine but it should re-render the chapter buttons to the new relevant book clicked.

The ‘selectedBook’ variable is updated but the state variable ‘chapter’ is still holding the value of the previous chapter and so the new state has the new book with the old chapter and fetches that chapter from the API and the relevant chapter buttons don’t get rendered.

2

Answers


  1. Chosen as BEST ANSWER

    I actually fixed it.

    It seems that the issue was with how I was updating state.

    I make two calls to the API. That's fine. The issue was that I was updating the same state, state.bible.bibleArray, from the two different API calls.

    So the second time I made the call to the API, I was overwriting my previous state.bible.bibleArray. What I did was I added a second array, newBibleArray, in the initialState in my bibleSlice.js in redux so that I can update state.bible.newBibleArray, using the data from the first API call in state.bible.bibleArray and finally displaying the text.


  2. Two things:

    1. Reset selectedBookChapter whenever a new book is chosen in the event handler (not in an effect)
    const onChangeBook = (id) => {
       setSelectedBook(book.id);
       setSelectedChapter(undefined); // undefined, or null, or similar
    }
    

    and then have all your buttons call this function

    1. There’s no "bookChapters" state – bookChapters is computed/derived as a consequence of a book being selected (or not), but it’s not state itself.
    const bookChapters = bibleArray.find(book => book.id === selectedBook)?.chapters || []
    

    That’s it. It gets recomputed on every render and that’s fine (unless you have a performance issue). You don’t need state to to hold bookChapters.

    It’s unlikely that chapterText is state as well, it shouldn’t be state and the effect shouldn’t exist.

    See this You might not need an effect

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