te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>react admin - useFormContext updates the input values, but not the state of the form - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

react admin - useFormContext updates the input values, but not the state of the form - Stack Overflow

programmeradmin1浏览0评论

useFormContext changes the value of the input and the state of the request payload sent to API.

import { FC, useEffect, useRef, useState } from "react";
import {
  ArrayInput,
  BooleanInput,
  Create,
  NumberInput,
  SelectInput,
  SimpleFormIterator,
  TextInput,
  required,
  AutocompleteArrayInput,
  ImageInput,
  useRedirect,
  Form,
  SimpleForm,
} from "react-admin";
import Box from "@mui/material/Box";
import { baseUrl } from "../dataProvider";
import { useFormContext } from "react-hook-form";
import { useOutsideAlerter } from "../hooks/useOutsideClick";

const initValue = {
  index: null,
  position: [0, 0],
};

const CreateForm: FC<{ ingredientChoices: { id: string; name: string }[] }> = ({
  ingredientChoices,
}) => {
  const [availableIngredients, setAvailableIngredients] = useState<
    Record<number, string>
  >({});
  const [nameValue, setNameValue] = useState<{ name: string; index: number }>({
    name: "",
    index: 0,
  });
  const [open, setOpen] = useState<{
    index: number | null;
    position: number[];
  }>(initValue);
  const { setValue } = useFormContext();
  const outside = useRef(null);
  useOutsideAlerter(outside, () => setOpen(initValue));

  const getChoices = () => {
    return Object.values(availableIngredients).map((value) => ({
      id: value,
      name: value,
    }));
  };

  const fetchAttributes = (id: string) => {
    fetch(`${baseUrl}/bo/ingredients/${id}`)
      .then((res) => res.json())
      .then((data) => {
        Object.entries(data).forEach(([key, value]) => {
          if (
            [
              "units",
              "value",
              "kcal",
              "protein",
              "carbs",
              "fat",
              "allergies",
            ].includes(key)
          ) {
            setValue(`ingredients.${nameValue.index}`, { [key]: value });
          }
        });
      });
  };

  return (
    <>
      {open.index === nameValue.index && (
        <Box
          ref={outside}
          boxShadow={2}
          sx={{
            position: "absolute",
            maxHeight: "250px",
            overflowY: "scroll",
            overflowX: "hidden",
            top: open.position[1] + 500,
            left: open.position[0],
            borderRadius: "10px",
            backgroundColor: "white",
            zIndex: 1000,
          }}
        >
          {ingredientChoices
            .filter(({ name }) =>
              nameValue.name ? name.includes(nameValue.name) : true,
            )
            .map(({ id, name }) => (
              <Box
                p={1}
                key={id}
                sx={{
                  cursor: "pointer",
                }}
                onClick={() => {
                  setValue(`ingredients.${nameValue.index}`, { name });
                  setOpen(initValue);
                  fetchAttributes(id);
                }}
              >
                {name}
              </Box>
            ))}
        </Box>
      )}
      <ArrayInput source="ingredients" validate={[required()]}>
        <SimpleFormIterator inline>
          <TextInput
            onChange={(e) => {
              const rect = e.target.getBoundingClientRect();
              setAvailableIngredients({
                ...availableIngredients,
                [e.target.id.split(".")[1]]: e.target.value,
              });
              setNameValue({
                name: e.target.value,
                index: +e.target.id.split(".")[1],
              });
              setOpen({
                index: +e.target.id.split(".")[1],
                position: [rect.left, rect.top],
              });
            }}
            source="name"
            validate={[required()]}
            helperText={false}
          />
          <TextInput
            validate={[required()]}
            source="units"
            helperText={false}
          />
          <NumberInput
            validate={[required()]}
            source="value"
            helperText={false}
          />
          <NumberInput
            validate={[required()]}
            source="kcal"
            helperText={false}
          />
          <NumberInput
            validate={[required()]}
            source="protein"
            helperText={false}
          />
          <NumberInput
            validate={[required()]}
            source="carbs"
            helperText={false}
          />
          <NumberInput
            validate={[required()]}
            source="fat"
            helperText={false}
          />
          <SelectInput choices={getChoices()} source="linkedIngredient" />
          <AutocompleteArrayInput
            fullWidth
            choices={allergenChoices}
            source="allergies"
          />
        </SimpleFormIterator>
      </ArrayInput>
    </>
  );
};

const RecipeCreate = () => {
  const redirect = useRedirect();
  const [ingredientChoices, setIngredientChoices] = useState<
    {
      id: string;
      name: string;
    }[]
  >([]);

  useEffect(() => {
    fetch(`${baseUrl}/bo/ingredients`)
      .then((res) => res.json())
      .then((data) => {
        setIngredientChoices(data);
      });
  }, []);

  return (
    <Create
      mutationOptions={{
        onSuccess: () => {
          redirect("/");
        },
      }}
    >
      <SimpleForm>
        <CreateForm ingredientChoices={ingredientChoices} />
      </SimpleForm>
    </Create>
  );
};

export default RecipeCreate;

This should basically create a dropdown of all the available ingredients in the databse and when one is clicked, the data in the form should prefill... But now I'm getting this weird case when I submit the prefilled form.

Screenshot from backoffice create form

I tried changing out the form provider library, none of them worked... Also tried moving the form itself out into a separate component, to see if the problem was the Form component

发布评论

评论列表(0)

  1. 暂无评论