4

I need to use a fetch inside the FormDataConsumer tag but it seems FormDataConsumer does not support async functions. This code didn't work for me:

<FormDataConsumer>
{
    async ({ formData, scopedFormData, getSource, ...rest }) => {
        return await fetch('/api/v1/attributes/'+scopedFormData.single_attributes_label)
        .then(res => res.json())
        .then(data => {
            console.log(JSON.stringify(data));
            //return JSON.stringify(data);
            resolve(JSON.stringify(data));
        });
        return JSON.stringify(scopedFormData);
    }
}
</FormDataConsumer>

I also checked this code and this one also didn't work:

async function getAttrItem(id) {
  return await fetch(`/api/v1/attributes/${id}`).then(response => response.json())
}

...

<FormDataConsumer>
{
    async ({ formData, scopedFormData, getSource, ...rest }) => {
        return await JSON.stringify(getAttrItem(scopedFormData.single_attributes_label));
    }
}
</FormDataConsumer>

But when I use this one, it works in the console:

<FormDataConsumer>
{
    ({ formData, scopedFormData, getSource, ...rest }) => {
        fetch('/api/v1/attributes/'+scopedFormData.single_attributes_label)
        .then(res => res.json())
        .then(data => {
            console.log(JSON.stringify(data));
            //return JSON.stringify(data);
            resolve(JSON.stringify(data));
        });
        return JSON.stringify(scopedFormData);
    }
}
</FormDataConsumer>

Should I use this FormDataConsumer for filling an object and then inside the other FormDataConsumer check the object?

3 Answers3

3

You might wanna do something like this:

const MyComponent = props => {
  const [data, setData] = useState();

  useEffect(() => {
    fetch("/api/v1/attributes/" + props.attribute)
      .then(res => res.json())
      .then(data => {
        setData(data);
      });
  }, [props.attribute]);

  if (!data) {
    return <someloadingindicator />;
  }

  // now you got your data. you can now return some component that uses the data here
};


// now in your component where using the FormDataConsumer
<FormDataConsumer>
  {({ formData, scopedFormData, getSource, ...rest }) => {
    return <MyComponent attribute={scopedFormData.single_attributes_label} />;
  }}
</FormDataConsumer>;
Moinul Hossain
  • 2,176
  • 1
  • 24
  • 30
2

While you can run JavaScript expressions in JSX, it is not a good pattern to bloat it with too much JavaScript logic within JSX. The above logic should be handled within the componentDidMount() lifecycle hook for class components, or in the useEffect hook, for functional components.

In your FormDataConsumer

componentDidMount() {
  fetch('/api/v1/attributes/'+scopedFormData.single_attributes_label)
    .then(res => res.json())
    .then(data => {
        console.log(data);
       // do the rest here
    });
}

or

useEffect(() => {
  fetch('/api/v1/attributes/'+scopedFormData.single_attributes_label)
    .then(res => res.json())
    .then(data => {
       console.log(data);
       // do the rest here
    });
 }, []);
wentjun
  • 40,384
  • 10
  • 95
  • 107
1

My issue was fixed with this code:

<FormDataConsumer>
    {
        ({ formData, scopedFormData, getSource, ...rest }) => {
            return scopedFormData && formData && "type" in formData && <ReferenceInput label="Attribute Label" source={getSource('single_attributes_label')} reference={`attributes`} filter={{ document_type: formData.type }}>
            <AutocompleteInput optionText="title" optionValue="id" />
            </ReferenceInput>
        }
    }
</FormDataConsumer>
<FormDataConsumer>
    {
        ({ formData, scopedFormData, getSource, ...rest }) => {
            return "type" in formData && "single_attributes_label" in scopedFormData && <AttribValue source={getSource('single_attributes_value')} reference={`attributes`} filter={{ document_type: formData.type, id: scopedFormData.single_attributes_label, method: "getOptions" }} attribute={scopedFormData.single_attributes_label} {...rest} />
        }
    }
</FormDataConsumer>

const AttribValue = props => {
  const [data, setData] = useState();
  console.log('props', props);
  useEffect(() => {
    fetch("/api/v1/attributes/" + props.attribute)
      .then(res => res.json())
      .then(data => {
        setData({ data });
      });
  }, [props.attribute, props.label]);

  if (!data) {
    return 'Please Wait...';
  }
  let newProp = Object.assign({}, props, { label: "Attributes Value" });
  return data.data.attribute_type == 'multiselect' ? <ReferenceArrayInput {...newProp}><AutocompleteArrayInput optionText="text" optionValue="id" /></ReferenceArrayInput> : <ReferenceInput {...newProp}><AutocompleteInput optionText="text" optionValue="id" /></ReferenceInput>;
};