વર્ડપ્રેસ ડેટા રેકોર્ડ્સમાં ફેરફાર કરવો

આ ભાગમાં આપણે અમારી એપમાં એડિટ ફીચર ઉમેરવા વિશે છે. આ રહ્યો એક ઝલક કે આપણે શું બનાવવાનો છે:

પગલું 1: એડિટ બટન ઉમેરો

અમે એડિટ બટન વગર એડિટ ફોર્મ બનાવી શકતા નથી, તેથી ચાલો પહેલા આપણો PagesList ઘટક માં એડિટ બટન ઉમેરવાથી શરૂઆત કરીએ:

import { Button } from '@wordpress/components';
import { decodeEntities } from '@wordpress/html-entities';

const PageEditButton = () => (
    <Button variant="primary">
        Edit
    </Button>
)

// Let's add the following lines of code to PagesList:
// <td>
//     <PageEditButton pageId={ page.id } />
// </td>
function PagesList( { hasResolved, pages } ) {
    if ( ! hasResolved ) {
        return <Spinner />;
    }
    if ( ! pages?.length ) {
        return <div>No results</div>;
    }

    return (
        <table className="wp-list-table widefat fixed striped table-view-list">
            <thead>
                <tr>
                    <td>Title</td>
                    <td style={{width: 120}}>Actions</td>
                </tr>
            </thead>
            <tbody>
                { pages?.map( ( page ) => (
                    <tr key={page.id}>
                        <td>{ decodeEntities( page.title.rendered ) }</td>
                        <td>
                            <PageEditButton pageId={ page.id } />
                        </td>
                    </tr>
                ) ) }
            </tbody>
        </table>
    );
}

PagesList માં એકમાત્ર ફેરફાર એ છે કે હવે એક નવી કોલમ ઉમેરવામાં આવી છે, જેનું લેબલ Actions છે:

પગલું 2: એડિટ ફોર્મ દર્શાવો

અમારું બટન સુંદર દેખાય છે, પણ હજી સુધી એ કોઈ કાર્ય કરતું નથી. એડિટ ફોર્મ દર્શાવવા માટે, પહેલાં આપણું એડિટ ફોર્મ બનાવવું પડશે – ચાલો એ બનાવીએ:

import { Button, TextControl } from '@wordpress/components';
export function EditPageForm( { pageId, onCancel, onSaveFinished } ) {
    return (
        <div className="my-gutenberg-form">
            <TextControl
                value=''
                label='Page title:'
            />
            <div className="form-buttons">
                <Button onClick={ onSaveFinished } variant="primary">
                    Save
                </Button>
                <Button onClick={ onCancel } variant="tertiary">
                    Cancel
                </Button>
            </div>
        </div>
    );
}

હવે ચાલો એ બટનને એ ફોર્મ દર્શાવવાનું બનાવીએ, જે આપણે હમણાં બનાવ્યું છે. કારણ કે આ ટ્યુટોરીયલ વેબ ડિઝાઇન પર ફોકસ નથી કરતું, તેથી આપણે બંનેને જોડવા માટે ઓછામાં ઓછી કોડ જરૂર હોય તેવો કોમ્પોનન્ટ ઉપયોગમાં લઈશું: Modal. આવો ચાલો હવે PageEditButton ને અનુકૂળ રીતે અપડેટ કરીએ:

import { Button, Modal, TextControl } from '@wordpress/components';

function PageEditButton({ pageId }) {
    const [ isOpen, setOpen ] = useState( false );
    const openModal = () => setOpen( true );
    const closeModal = () => setOpen( false );
    return (
        <>
            <Button
                onClick={ openModal }
                variant="primary"
            >
                Edit
            </Button>
            { isOpen && (
                <Modal onRequestClose={ closeModal } title="Edit page">
                    <EditPageForm
                        pageId={pageId}
                        onCancel={closeModal}
                        onSaveFinished={closeModal}
                    />
                </Modal>
            ) }
        </>
    )
}

હવે જ્યારે તમે Edit બટન ક્લિક કરો છો, ત્યારે તમને નીચે મુજબનું Modal દેખાશે:

શાનદાર! હવે અમારા પાસે કામ કરવા માટેનું મૂળભૂત યૂઝર ઈન્ટરફેસ તૈયાર છે.

પગલું 3: ફોર્મમાં પેજની વિગતો ભરો

અમે ઈચ્છીએ છીએ કે EditPageForm હાલ જે પેજ સંપાદિત થઈ રહ્યો છે તેનુ શીર્ષક (title) બતાવે. તમે કદાચ જોયું હશે કે તેને page તરીકે prop મળતી નથી, ફક્ત pageId મળે છે પણ એ ઠીક છે. ગૂટેનબર્ગ ડેટા આપણને કોઈપણ કોમ્પોનન્ટમાંથી એન્ટિટી રેકોર્ડ્સ સરળતાથી એક્સેસ કરવાની મંજુરી આપે છે.

આ કિસ્સામાં, આપણે getEntityRecord સિલેક્ટર નો ઉપયોગ કરવાની જરૂર છે. MyFirstApp માં અગાઉ કરવામાં આવેલ getEntityRecords કોલના કારણે record ની યાદી પહેલેથી જ ઉપલબ્ધ છે, એટલે અહીં કોઈ નવી HTTP request થશે નહીં. આપણે તરત જ કેશ રેકોર્ડ મેળવીશું.

તમારા બ્રાઉઝરના ડેવલપમેન્ટ ટૂલ્સમાં તમે તેને કેવી રીતે અજમાવી શકો છો તે અહીં છે:

wp.data.select( 'core' ).getEntityRecord( 'postType', 'page', 9 );  // Replace 9 with an actual page ID

પ્રતિબિંબ

ગૂટેનબર્ગ બ્લોકમાં વર્ડપ્રેસ ડેટા યૂટિલિટીઝનો આધાર રાખવાથી, એડિટર દ્વારા પહેલાથી જ લાવેલી ડેટાનો પુનઃઉપયોગ કરવાની મંજૂરી આપે છે. આનો અર્થ એ થાય છે કે ઓછા લોડિંગ સૂચકો દેખાશે અને અંતિમ યુઝરને વધુ સારું અને ઝડપી અનુભવ મળશે.

ચાલો, તે અનુસાર EditPageForm ને અનુરૂપ અપડેટ કરીએ:

export function EditPageForm( { pageId, onCancel, onSaveFinished } ) {
    const page = useSelect(
        select => select( coreDataStore ).getEntityRecord( 'postType', 'page', pageId ),
        [pageId]
    );
    return (
        <div className="my-gutenberg-form">
            <TextControl
                label='Page title:'
                value={ page.title.rendered }
            />
            { /* ... */ }
        </div>
    );
}

હવે તે આ રીતે દેખાવું જોઈએ:

પગલું 4: પેજ શીર્ષક ક્ષેત્ર એડિટેબલ બનાવો

અમારા પેજ ટાઇટલ ફીલ્ડમાં એક સમસ્યા છે: તમે તેને એડિટ કરી શકતા નથી. તેને ફિક્સ વેલ્યુ મળે છે પરંતુ લખતી વખતે તે અપડેટ થતું નથી. માટે આપણે onChange હેન્ડલર ની જરૂર છે.

તમારે આ જેવા પેટર્ન પહેલા પણ બીજા React એપ્સમાં જોયો હશે. તેને “Controlled Component” તરીકે ઓળખવામાં આવે છે:

export function VanillaReactForm({ initialTitle }) {
    const [title, setTitle] = useState( initialTitle );
    return (
        <TextControl
            value={ title }
            onChange={ setTitle }
        />
    );
}

ગૂટેનબર્ગ ડેટામાં માં એન્ટિટી રેકોર્ડ્સ ને અપડેટ કરવું મળતાવળતું છે, પણ setTitle નો ઉપયોગ કરીને લોકલ (component level) state માં value સ્ટોર કરવાની જગ્યાએ, આપણે editEntityRecord એક્શનનો ઉપયોગ કરીએ છીએ, જે updates ને Redux state માં સ્ટોર કરે છે. નીચે બતાવેલ રીતે તમે તમારા બ્રાઉઝર ના ડેવલપમેન્ટ ટૂલ્સમાં તેને ટ્રાય કરી શકો છો:

// We need a valid page ID to call editEntityRecord, so let's get the first available one using getEntityRecords.
const pageId = wp.data.select( 'core' ).getEntityRecords( 'postType', 'page' )[0].id;

// Update the title
wp.data.dispatch( 'core' ).editEntityRecord( 'postType', 'page', pageId, { title: 'updated title' } );

આ સમયે તમે પૂછો કે editEntityRecordનો ઉપયોગ useState કરતા કેટલો સારો છે? તો તેનો જવાબ એ છે કે તે તમને કેટલીક એવી સુવિધાઓ આપે છે જે useState આપતું નથી.

સૌપ્રથમ, આપણે data મેળવવા જેટલી સહેલાઈથી updates સેવ કરી શકીએ છીએ અને ખાતરી આપી શકીએ છીએ કે બધા cache યોગ્ય રીતે અપડેટ થશે.

બીજું, editEntityRecord દ્વારા કરવામાં આવેલી બદલાવ changes સરળતાથી undo અને redo actions દ્વારા પાછાં ફેરવી શકાય છે.

છેલ્લે, કારણ કે બદલાવ Redux state માં જીવે છે, તે “જાહેર” હોય છે અને અન્ય ઘટકો (components) દ્વારા એક્સેસ કરી શકાય છે. ઉદાહરણ તરીકે, PagesList હાલમાં એડિટ થતો શીર્ષક (title) દર્શાવી શકે છે.

આ છેલ્લી વાતને વધુ સ્પષ્ટ કરવા માટે, ચાલો જુઓ કે શું થાય છે જ્યારે આપણે getEntityRecord નો ઉપયોગ કરીને તાજેતરમાં અપડેટ થયેલા entity record ને એક્સેસ કરીએ છીએ:

wp.data.select( 'core' ).getEntityRecord( 'postType', 'page', pageId ).title

તે એડિટ્સ બતાવતું નથી. એવું કેમ થાય છે?

સાચું છે, એ getEntityRecord() દ્વારા પાછું મળેલ ડેટા રેન્ડર કરે છે. જો getEntityRecord() એ અપડેટ થયેલું શીર્ષક (title) દર્શાવતું હોત, તો વપરાશકર્તા જે કંઈ TextControl માં ટાઇપ કરે તે તરત જ માં પણ દેખાતું. પણ આપણે આવું નહિં ઈચ્છતા. એડિટ કરેલી માહિતી ત્યારે સુધી બહાર ફેલાવવી નહિ જોઈએ જ્યાં સુધી વપરાશકર્તા તે સાચવે નહિ.

ગૂટેનબર્ગ ડેટા આ સમસ્યાનું ઉકેલ લાવે છે એ રીતે કે તે Entity Records અને Edited Entity Records વચ્ચે તફાવત કરીને કરે છે. Entity Records એ API માંથી મળેલા મૂળ ડેટાને દર્શાવે છે અને કોઈપણ લોકલ ફેરફારોને અવગણે છે, જ્યારે Edited Entity Records એ એજ ડેટા પર લોકલ એડિટ્સ પણ દર્શાવે છે. આ બંને રેકોર્ડ્સ એકસાથે Redux state માં રહેલા હોય છે. તેથી તમે એકજ સમયે મૂળ ડેટા અને એડિટ કરેલું ડેટા જુદી-જુદી રીતે મેળવી શકો છો.

ચાલો હવે જોઈએ કે જો આપણે getEditedEntityRecord કોલ કરીએ તો શું પરિણામ આવે છે.

wp.data.select( 'core' ).getEditedEntityRecord( 'postType', 'page', pageId ).title
// "updated title"

wp.data.select( 'core' ).getEntityRecord( 'postType', 'page', pageId ).title
// { "rendered": "<original, unchanged title>", "raw": "..." }

જેમ તમે જોઈ શકો છો, Entity Record માં title એક ઑબ્જેક્ટ હોય છે, જ્યારે Edited Entity Record માં title એક string હોય છે.

આ ઈચ્છાપૂર્વક જ બનાવવામાં આવ્યું છે. title, excerpt અને content જેવા ફીલ્ડમાં ઘણીવાર શૉર્ટકોડ કે ડાયનામિક બ્લૉક્સ હોય શકે છે, એટલે તેઓને ફક્ત સર્વર પર જ યોગ્ય રીતે રેન્ડર કરી શકાય છે. આવાં ફીલ્ડ્સ માટે REST API બંને – કાચી અને રેન્ડર થયેલી value આપે છે. ઉદાહરણ તરીકે, બ્લૉક એડિટરમાં content.rendered નો ઉપયોગ વિઝ્યુઅલ પૂર્વદર્શન માટે થાય છે અને content.raw નો ઉપયોગ કોડ એડિટરને બતાવવા માટે થાય છે.

તો પછી Edited Entity Record નું content string કેમ હોય છે? કારણ કે JavaScript અનિયંત્રિત બ્લૉક માર્કઅપને યોગ્ય રીતે રેન્ડર કરી શકતું નથી, તે ફક્ત markup સમાવિષ્ટ જ સ્ટોર કરે છે, રેન્ડર કરેલું ભાગ નહીં. અને આ raw markup એક string સ્વરૂપમાં હોય છે, તેથી આખું ફીલ્ડ string બની જાય છે.

હવે આપણે તે અનુસાર EditPageForm ને અનુકૂળ રીતે અપડેટ કરી શકીએ છીએ. જેમ આપણે useSelect નો ઉપયોગ કરીને selectors ને ઍક્સેસ કરીએ છીએ, તેમ જ actions ને ઍક્સેસ કરવા માટે આપણે useDispatch hook નો ઉપયોગ કરી શકીએ છીએ.

import { useDispatch } from '@wordpress/data';

export function EditPageForm( { pageId, onCancel, onSaveFinished } ) {
    const page = useSelect(
        select => select( coreDataStore ).getEditedEntityRecord( 'postType', 'page', pageId ),
        [ pageId ]
    );
    const { editEntityRecord } = useDispatch( coreDataStore );
    const handleChange = ( title ) => editEntityRecord( 'postType', 'page', pageId, { title } );

    return (
        <div className="my-gutenberg-form">
            <TextControl
                label="Page title:"
                value={ page.title }
                onChange={ handleChange }
            />
            <div className="form-buttons">
                <Button onClick={ onSaveFinished } variant="primary">
                    Save
                </Button>
                <Button onClick={ onCancel } variant="tertiary">
                    Cancel
                </Button>
            </div>
        </div>
    );
}

અમે ફેરફારોને ટ્રેક કરવા માટે editEntityRecord action નો ઉપયોગ કરીને onChange handler ઉમેર્યો છે, અને ત્યારબાદ selector ને getEditedEntityRecord માં બદલ્યો છે જેથી page.title હંમેશા ફેરફારોને દર્શાવે.

હવે આ પ્રમાણે દેખાય છે:

પગલું 5: ફોર્મ ડેટા સેવ કરો

હવે જ્યારે આપણે પેજ ટાઈટલમાં ફેરફાર કરી શકીએ છીએ, ચાલો એ પણ ખાતરી કરીએ કે આપણે તેને સાચવી પણ શકીએ. ગૂટેનબર્ગ ડેટા માં, WordPress REST API પર ફેરફારો સાચવવા માટે saveEditedEntityRecord action નો ઉપયોગ કરીએ છીએ. આ એક રિક્વેસ્ટ મોકલે છે, પરિણામનું પ્રોસેસિંગ કરે છે અને Redux state માં cache થયેલ ડેટાને અપડેટ કરે છે.

આ રહી એક ઉદાહરણ કોડ લાઇન જે તમે તમારા બ્રાઉઝર ના ડેવલપમેન્ટ ટૂલ્સમાં ટ્રાય કરી શકો છો:

// Replace 9 with an actual page ID
wp.data.dispatch( 'core' ).editEntityRecord( 'postType', 'page', 9, { title: 'updated title' } );
wp.data.dispatch( 'core' ).saveEditedEntityRecord( 'postType', 'page', 9 );

ઉપરોક્ત કોડ સ્નિપેટે નવા ટાઈટલને સાચવી દીધું છે. અગાઉના સમયે તફાવત તરીકે, હવે getEntityRecord અપડેટ થયેલ ટાઈટલ દર્શાવે છે:

// Replace 9 with an actual page ID
wp.data.select( 'core' ).getEntityRecord( 'postType', 'page', 9 ).title.rendered
// "updated title"

Entity Records હવે REST API રિક્વેસ્ટ પૂર્ણ થતાં જ કોઈપણ સંગ્રહિત ફેરફારો દર્શાવવા માટે એન્ટિટી રેકોર્ડ્સ અપડેટ થાય છે.

આ EditPageForm નું દેખાવ જ્યારે તેમાં કાર્યરત Save બટન ઉમેરવામાં આવ્યું છે:

export function EditPageForm( { pageId, onCancel, onSaveFinished } ) {
    // ...
    const { saveEditedEntityRecord } = useDispatch( coreDataStore );
    const handleSave = () => saveEditedEntityRecord( 'postType', 'page', pageId );

    return (
        <div className="my-gutenberg-form">
            {/* ... */}
            <div className="form-buttons">
                <Button onClick={ handleSave } variant="primary">
                    Save
                </Button>
                {/* ... */}
            </div>
        </div>
    );
}

આ કાર્ય કરે છે, પરંતુ હજુ પણ એક વસ્તુ સુધારવાની બાકી છે: ફોર્મ મોડલ આપમેળે બંધ થતું નથી કારણ કે આપણે ક્યારેય onSaveFinished ને કૉલ કર્યું નથી. આપણા માટે નસીબદાર છે, saveEditedEntityRecord એક વચન આપે છે જે સેવ ઓપરેશન પૂર્ણ થયા પછી resolve થાય છે. ચાલો EditPageForm માં તેનો લાભ લઈએ:

export function EditPageForm( { pageId, onCancel, onSaveFinished } ) {
    // ...
    const handleSave = async () => {
        await saveEditedEntityRecord( 'postType', 'page', pageId );
        onSaveFinished();
    };
    // ...
}

પગલું 6: ભૂલોને હેન્ડલ કરો

અમે આશાવાદી રીતે ધારણા લીધી હતી કે સેઇવ ઑપરેશન હંમેશા સફળ થશે. દુર્ભાગ્યવશ, તે ઘણા રીતે નિષ્ફળ જઈ શકે છે:

  • વેબસાઇટ ડાઉન હોઈ શકે છે
  • અપડેટ અમાન્ય હોઈ શકે છે
  • તે દરમિયાન કોઈ બીજા દ્વારા પેજ કાઢી નાખવામાં આવ્યું હોઈ શકે છે

જ્યારે આમાંથી કોઈ પણ ઘટના બને ત્યારે યુઝરને જણાવવા માટે, આપણે બે ફેરફારો કરવાની જરૂર પડશે. જો અપડેટ નિષ્ફળ જાય ત્યારે આપણે ફોર્મ મોડલ આપમેળે બંધ નહીં થવું જોઈએ. saveEditedEntityRecord દ્વારા પરત કરાયેલ વચન અપડેટેડ રેકોર્ડ સાથે resolve થાય છે તો અપડેટ ખરેખર કામ કરે. જ્યારે કંઈક ખોટું થાય છે, ત્યારે તે ખાલી મૂલ્ય સાથે ઉકેલાય છે. ચાલો મોડલને ખુલ્લું રાખવા માટે તેનો ઉપયોગ કરીએ:

export function EditPageForm( { pageId, onSaveFinished } ) {
    // ...
    const handleSave = async () => {
        const updatedRecord = await saveEditedEntityRecord( 'postType', 'page', pageId );
        if ( updatedRecord ) {
            onSaveFinished();
        }
    };
    // ...
}

સરસ! હવે, ચાલો એક ભૂલ સંદેશ પ્રદર્શિત કરીએ. નિષ્ફળતાની વિગતો getLastEntitySaveError selector નો ઉપયોગ કરીને મેળવી શકાય છે:

// Replace 9 with an actual page ID
wp.data.select( 'core' ).getLastEntitySaveError( 'postType', 'page', 9 )

EditPageForm માં આપણે તેનો ઉપયોગ કેવી રીતે કરી શકીએ તે અહીં છે:

export function EditPageForm( { pageId, onSaveFinished } ) {
    // ...
    const { lastError, page } = useSelect(
        select => ({
            page: select( coreDataStore ).getEditedEntityRecord( 'postType', 'page', pageId ),
            lastError: select( coreDataStore ).getLastEntitySaveError( 'postType', 'page', pageId )
        }),
        [ pageId ]
    )
    // ...
    return (
        <>
            {/* ... */}
            { lastError ? (
                <div className="form-error">
                    Error: { lastError.message }
                </div>
            ) : false }
            {/* ... */}
        </>
    );
}

સરસ! EditPageForm હવે ભૂલોથી સંપૂર્ણપણે વાકેફ છે.

ચાલો તે ભૂલ સંદેશને કાર્યમાં જોઈએ. આપણે એક અમાન્ય અપડેટ ટ્રિગર કરીશું અને તેને નિષ્ફળ થવા દઈશું. post title તોડવું મુશ્કેલ છે, તેથી ચાલો તેના બદલે date પ્રોપર્ટી -1 પર સેટ કરીએ – એ તો ચોક્કસ રીતે માન્યતા માં ભૂલ છે:

export function EditPageForm( { pageId, onCancel, onSaveFinished } ) {
    // ...
    const handleChange = ( title ) => editEntityRecord( 'postType', 'page', pageId, { title, date: -1 } );
    // ...
}

જ્યારે તમે પેજને રિફ્રેશ કરો પછી, ફોર્મ ખોલો, title બદલો અને સેવ બટન ક્લિક કરો, તમે નીચે આપેલો ભૂલ સંદેશ જોઈ શકશો:

શાનદાર! હવે આપણે handleChange નું અગાઉનું સંસ્કરણ પુનઃસ્થાપિત કરી શકીએ છીએ અને આગળના પગલાં તરફ વધી શકીએ છીએ.

પ્રતિબિંબ

REST API ની ભૂલ સંભાળવાની પરીક્ષણ પ્રક્રિયા અત્યંત મહત્વપૂર્ણ છે, પરંતુ ઘણી વખત તેમાં થોડી સર્જનાત્મકતા જરૂરી બને છે. EditPageForm માં એવા ઘણાં ઓછા ઇનપુટ્સ છે જે ખોટા break પડે, તેથી ઉપર આપેલ ઉદાહરણમાં ખોટું અપડેટ દર્શાવવાં માટે જેણે ફરજપૂર્વક એક જુદી ફીલ્ડનો ઉપયોગ કર્યો હતો. date ફિલ્ડનો પસંદગી કરવામાં આવી હતી કારણ કે તે /pages REST API endpoint reference માં દેખાતી પહેલી validated ફિલ્ડ હતી.

પગલું 7: સ્ટેટસ ઇન્ડિકેટર ઉમેરો

આપણા ફોર્મમાં એક છેલ્લી સમસ્યા બાકી છે: કોઈ વિઝ્યુઅલ ફીડબેક નથી. અમે ચોક્કસ રીતે કહી શકતા નથી કે સેવ બટન કાર્યરત થયું કે નહીં, જ્યાં સુધી કે તો ફોર્મ બંધ ન થઈ જાય અથવા ભૂલ સંદેશ ન દેખાય નહીં આવે.

અમે હવે આ સ્થિતિ સ્પષ્ટ કરવા જઈ રહ્યા છીએ અને યુઝરને બે અવસ્થાઓ દર્શાવીશું: સેવ થઈ રહ્યું છે અને કોઈ ફેરફાર મળ્યા નથી. તેના માટે ઉપયોગી selectors છે: isSavingEntityRecord અને hasEditsForEntityRecord. getEntityRecord ની જેમ, આ selectors કોઈ HTTP requests નથી મોકલતા, પરંતુ ફક્ત વર્તમાન entity record ની સ્થિતિ જ પરત આપે છે.

ચાલો તેમને EditPageForm માં વાપરીએ:

export function EditPageForm( { pageId, onSaveFinished } ) {
    // ...
    const { isSaving, hasEdits, /* ... */ } = useSelect(
        select => ({
            isSaving: select( coreDataStore ).isSavingEntityRecord( 'postType', 'page', pageId ),
            hasEdits: select( coreDataStore ).hasEditsForEntityRecord( 'postType', 'page', pageId ),
            // ...
        }),
        [ pageId ]
    )
}

હવે આપણે સેવિંગ ચાલુ હોય ત્યારે સ્પિનર દર્શાવવા માટે isSaving અને hasEdits નો ઉપયોગ કરી શકીએ છીએ અને જ્યારે કોઈ એડિટ્સ ન હોય ત્યારે સેવ બટનને ગ્રે આઉટ કરી શકીએ છીએ:

export function EditPageForm( { pageId, onSaveFinished } ) {
    // ...
    return (
        // ...
        <div className="form-buttons">
            <Button onClick={ handleSave } variant="primary" disabled={ ! hasEdits || isSaving }>
                { isSaving ? (
                    <>
                        <Spinner/>
                        Saving
                    </>
                ) : 'Save' }
            </Button>
            <Button
                onClick={ onCancel }
                variant="tertiary"
                disabled={ isSaving }
            >
                Cancel
            </Button>
        </div>
        // ...
    );
}

નોંધ રાખો કે જ્યારે કોઈ ફેરફાર થયા ન હોય અને પેજ હાલમાં સેવ થઈ રહ્યું હોય, ત્યારે અમે સેવ બટન નિષ્ક્રિય કરીએ છીએ. આ ઉપાય એ માટે છે કે યુઝર ભૂલથી બટનને અજાણતાં બે વાર ન દબાવે.

ઉપરાંત, @wordpress/data માં સેવ પ્રક્રિયાને વચ્ચે અટકાવવાનું સપોર્ટેડ નથી, એટલે અમે કેન્સલ બટન પણ શરતી રૂપે નિષ્ક્રિય કર્યું છે.

તે ક્રિયામાં કેવું દેખાય છે તે અહીં છે:

બધા ભાગોને જોડીને હવે આપણે પૂર્ણ કરવું છે

સારી બાબત એ છે કે, બધા ભાગો હવે યોગ્ય રીતે જોડાઈ ગયા છે! આ પ્રકરણમાં આપણે જે કંઈ બનાવ્યું છે તે બધું એક જગ્યાએ અહીં આપવામાં આવ્યું છે:

import { useDispatch } from '@wordpress/data';
import { Button, Modal, TextControl } from '@wordpress/components';

function PageEditButton( { pageId } ) {
    const [ isOpen, setOpen ] = useState( false );
    const openModal = () => setOpen( true );
    const closeModal = () => setOpen( false );
    return (
        <>
            <Button onClick={ openModal } variant="primary">
                Edit
            </Button>
            { isOpen && (
                <Modal onRequestClose={ closeModal } title="Edit page">
                    <EditPageForm
                        pageId={ pageId }
                        onCancel={ closeModal }
                        onSaveFinished={ closeModal }
                    />
                </Modal>
            ) }
        </>
    );
}

export function EditPageForm( { pageId, onCancel, onSaveFinished } ) {
    const { page, lastError, isSaving, hasEdits } = useSelect(
        ( select ) => ( {
            page: select( coreDataStore ).getEditedEntityRecord( 'postType', 'page', pageId ),
            lastError: select( coreDataStore ).getLastEntitySaveError( 'postType', 'page', pageId ),
            isSaving: select( coreDataStore ).isSavingEntityRecord( 'postType', 'page', pageId ),
            hasEdits: select( coreDataStore ).hasEditsForEntityRecord( 'postType', 'page', pageId ),
        } ),
        [ pageId ]
    );

    const { saveEditedEntityRecord, editEntityRecord } = useDispatch( coreDataStore );
    const handleSave = async () => {
        const savedRecord = await saveEditedEntityRecord( 'postType', 'page', pageId );
        if ( savedRecord ) {
            onSaveFinished();
        }
    };
    const handleChange = ( title ) =>  editEntityRecord( 'postType', 'page', page.id, { title } );

    return (
        <div className="my-gutenberg-form">
            <TextControl
                label="Page title:"
                value={ page.title }
                onChange={ handleChange }
            />
            { lastError ? (
                <div className="form-error">Error: { lastError.message }</div>
            ) : (
                false
            ) }
            <div className="form-buttons">
                <Button
                    onClick={ handleSave }
                    variant="primary"
                    disabled={ ! hasEdits || isSaving }
                >
                    { isSaving ? (
                        <>
                            <Spinner/>
                            Saving
                        </>
                    ) : 'Save' }
                </Button>
                <Button
                    onClick={ onCancel }
                    variant="tertiary"
                    disabled={ isSaving }
                >
                    Cancel
                </Button>
            </div>
        </div>
    );
}

Suggestions

Found a typo, grammar error or outdated screenshot? Contact us.