0

I'm trying to fetch some data inside useEffect and when the data is received I want to set a certain state with useState. Data correctly returns from the server. However this doesn't work. Here's the code:

const [sharingLink, setSharingLink] = React.useState(null);

React.useEffect(() => {
    client.query({
        query: queryGetReferalData
    }).then(result => {
        console.warn(result); // correct response
        setSharingLink(result.data.referralsystem.shareUrl);
        console.warn(sharingLink); // null
    });
}, []);

Here's the whole component:

import React from 'react';
import styled from 'styled-components';
import { i18n } from 'Helpers';

import { Button } from './Button';
import { ButtonLink } from './ButtonLink';
import { Heading } from './Heading';
import { Input } from './Input';

import Copy from './icons/Copy';
import Facebook from './icons/Facebook';
import Twitter from './icons/Twitter';
import WhatsApp from './icons/WhatsApp';

import client from '@client/apollo';
import queryGetReferalData from './schemas/queryGetReferalData.graphql';

const Root = styled.div`
    padding: 48px;
    padding-top: 32px;

    display: flex;
    align-items: center;
    justify-content: space-between;

    box-shadow: 0px 10px 30px rgba(27, 50, 85, 0.1);
    border-radius: 4px;

    background-color: #FFFFFF;
`;

const Pane = styled.div`

`;

const Row = styled.div`
    display: flex;

    & > * + * {
        margin-left: 10px;
    }
`;

export const Form = () => {
    const [sharingLink, setSharingLink] = React.useState(null);

    const facebookSharingLink =
        sharingLink && `https://www.facebook.com/sharer/sharer.php?${encodeURIComponent(sharingLink)}`;

    const twitterSharingLink = 
        sharingLink && `http://www.twitter.com/share?url=${encodeURIComponent(sharingLink)}`;

    const whatsAppSharingLink = 
        sharingLink && `whatsapp://send?text=${encodeURIComponent(sharingLink)}`;

    React.useEffect(() => {
        client.query({
            query: queryGetReferalData
        }).then(result => {
            console.warn(result);
            setSharingLink(result.data.referralsystem.shareUrl);
            console.warn(sharingLink);
        });
    }, []);

    return (
        <Root>
            <Pane>
                <Heading>
                    { i18n._('Your invitational link') }
                </Heading>
                <Row>
                    <Input disabled={sharingLink === null} value={sharingLink} />
                    <Button icon={<Copy />}>
                        { i18n._('COPY') }
                    </Button>
                </Row>
            </Pane>
            <Pane>
                <Heading>
                    { i18n._('Or share via social') }
                </Heading>
                <Row>
                    <ButtonLink
                        backgroundColor='#5A79B5'
                        icon={<Facebook />}
                        href={facebookSharingLink}
                    >
                        { i18n._('Facebook') }
                    </ButtonLink>
                    <ButtonLink
                        backgroundColor='#52A6DB'
                        icon={<Twitter />}
                        href={twitterSharingLink}
                    >
                        { i18n._('Twitter') }
                    </ButtonLink>
                    <ButtonLink
                        backgroundColor='#0DC455'
                        icon={<WhatsApp />}
                        href={whatsAppSharingLink}
                    >
                        { i18n._('WhatsApp') }
                    </ButtonLink>
                </Row>
            </Pane>
        </Root>
    );
};

The component also renders like sharingLink is null.

  1. Why is this happening?
  2. What do I do to make this work?
keyfan
  • 23
  • 9
  • 1
    `setState` async operaion, you can move `console.warn(sharingLink)` under `useEffect` and see correct result – Nikita Madeev Jul 13 '20 at 09:11
  • @NikitaMadeev but how do I set state in such way that component renders the value I got from the server? – keyfan Jul 13 '20 at 09:17
  • you are doing everything right, just at the time of the request `sharingLink` is `null` (init `React.useState(null)`), you need to consider this in the render method – Nikita Madeev Jul 13 '20 at 09:19
  • It still renders as if the state was null even though I clearly call setState inside the callback – keyfan Jul 13 '20 at 09:22
  • What is the shape of `result` when you. log it in the callback? If you `useEffect(() => console.log(sharingLink), [sharingLink]);` what is logged when the component is running and the state is updated? – Drew Reese Jul 13 '20 at 09:30
  • @DrewReese it logs the correct data. How do I make it render now? – keyfan Jul 13 '20 at 09:33
  • Please update with complete component code. Something else must be going on if you are correctly updating state and still seeing unexpected results. – Drew Reese Jul 13 '20 at 09:34
  • Nothing stands out as abnormal to me. So when you added the above effect to log `sharingLink` and the component rerendered you see the correct `sharingLink` state (but the UI isn't updating)? – Drew Reese Jul 13 '20 at 09:52
  • @DrewReese exactly – keyfan Jul 13 '20 at 09:54
  • Interesting. If you see the updated state in the effect, then that means the `Form` component rerendered. Does the `Input` become enabled? Can you share the other components that consume `sharingLink`, like `ButtonLink`? Maybe they just aren't rerendering. Short of this, can you try to get a running codesandbox that reproduces this UI issue so that we can see it running and better debug? – Drew Reese Jul 13 '20 at 09:59
  • @DrewReese the most interesting part is that it works with fetch: https://codesandbox.io/s/loving-tree-358gx?file=/src/App.js It seems like there's a problem with my graphql library. But I mean a promise is just a promise. Or is it? – keyfan Jul 13 '20 at 10:07
  • @DrewReese my other components are just simple functional components with styling and none of them have even a single hook – keyfan Jul 13 '20 at 10:14

1 Answers1

0

I had some code that was adding to the DOM in the parent component. When I remove it, everything works.

Adding to the DOM in the component, doesn't matter if it's into useEffect or not, somehow messes up hooks even though you add HTML to something completely unrelated to react I guess.

I had this structure:

<body>
 <div id="page">
  <div id="root">
   <CustomReactElement />
  </div>
 </div>
<body>

The code inside CustomReactElement was adding markup to the 'page'. I changed the code from setting an innerHTML to appendChild() and everything worked.

keyfan
  • 23
  • 9