Help

Re: Reload app on useRecordActionData

Solved
Jump to Solution
2005 1
cancel
Showing results for 
Search instead for 
Did you mean: 
Brian_Frank
6 - Interface Innovator
6 - Interface Innovator

Resurfacing the discussion from Reload app on useRecordActionData hook since it was never really solved.

I have the same issue. I’ve tried useEffect() and useState() to store and update the state, but Airtable’s button action appears to generate recordActionData one time. So, in my case, I can get the record data, create a new record on a separate table and attach it to the original record via a linked record field, and expand the new record for editing, and I report back to the user with a message indicating the name of the newly created record. That all works, but the app itself just stays on that final display state, saying the name of the new record. When the user hits the button again, nothing happens. No new recordActionData is sent, so the app’s useEffect function is not triggered again.

Here’s the bulk of my working code:

function SourceTrackerApp() {
    const recordActionData = useRecordActionData();
    
    if (recordActionData === null) {
        return <Box padding={2}>Click the "New Source" button in an assignment record to add a source.</Box>
    }
    
    return <RecordActionData data={recordActionData} />;
}

function RecordActionData({data}) {
    const session = useSession();
    const base = useBase();
    const table = base.getTableByIdIfExists(data.tableId);
    const sourceTable = base.getTableByIdIfExists('XXXXX');
    const view = table && table.getViewByIdIfExists(data.viewId);
    const record = useRecordById(view, data.recordId);
    const itemsProduced = sourceTable.getFieldById('XXXXX');
    const interviewer = sourceTable.getFieldById('XXXXX');
    const [source, setSource] = useState();

    if (!(table && view && record)) {
        return <Box padding={2}>Table, view or record was deleted.</Box>
    }
    
    // Check if user can create a specific record
    const updateFields = {
        [itemsProduced.id]: [{id: record.id}],
        [interviewer.id]: session.currentUser
    }
    const createRecordCheckResult = sourceTable.checkPermissionsForCreateRecord(updateFields);
    if (!createRecordCheckResult.hasPermission) {
        return <Box padding={2}>
                {createRecordCheckResult.reasonDisplayString}
            </Box>
    } else {
        useEffect(() => {
            const createSource = async () => {
                const newRecordID = await sourceTable.createRecordAsync(updateFields);
                const newSourceQuery = await sourceTable.selectRecordsAsync();
                const newSource = newSourceQuery.getRecordById(newRecordID);
                expandRecord(newSource);
                setSource(newSource.name);
            }
            createSource();
        }, [data.recordId]);

        return (
            <Box padding={2}>
                { source && `New source created: ${source}` }
            </Box>
        )
    }
}
1 Solution

Accepted Solutions
Billy_Littlefie
7 - App Architect
7 - App Architect

Hi @Brian_Frank ,

Thanks for writing in and providing a code sample! Looking at the code, I see a couple of things –

First, the useEffect hook you’ve setup is watching data.recordId, which is a string. I think React’s equality checks when comparing dependant keys between renders will consider this to be equivalent if the same record was clicked, so the effect wouldn’t execute. The SDK does send a new recordActionData object on subsequent button presses, even on the same record, but we need a means of comparing the objects themselves because its possible for their internals to be equal. If you change the dependent key to the entire object that comes from useRecordActionData (in this case, just data), it should trigger because even if the object is deeply equal, it’s still a new/different object.

Second, and I’m not sure this is impacting anything here, but I’d recommend avoiding putting React hook calls in conditions as it can result in unexpected behavior. See Rules of Hooks for additional context.

Hope this is helpful!

Cheers,
Billy

See Solution in Thread

2 Replies 2
Billy_Littlefie
7 - App Architect
7 - App Architect

Hi @Brian_Frank ,

Thanks for writing in and providing a code sample! Looking at the code, I see a couple of things –

First, the useEffect hook you’ve setup is watching data.recordId, which is a string. I think React’s equality checks when comparing dependant keys between renders will consider this to be equivalent if the same record was clicked, so the effect wouldn’t execute. The SDK does send a new recordActionData object on subsequent button presses, even on the same record, but we need a means of comparing the objects themselves because its possible for their internals to be equal. If you change the dependent key to the entire object that comes from useRecordActionData (in this case, just data), it should trigger because even if the object is deeply equal, it’s still a new/different object.

Second, and I’m not sure this is impacting anything here, but I’d recommend avoiding putting React hook calls in conditions as it can result in unexpected behavior. See Rules of Hooks for additional context.

Hope this is helpful!

Cheers,
Billy

Thanks @Billy_Littlefield! data instead of data.recordId in the useEffect dependency array worked like a charm. Now I just need to figure out how to refactor it to avoid having the useEffect() hook inside a conditional statement. I’ll try to repost some of my code here for others’ benefit when I figure that out.