nutui-react icon indicating copy to clipboard operation
nutui-react copied to clipboard

Cascader 在onChange得到的value值发生改变后(比如 value.map(i=>i)),Cascader不再受控

Open lei14370 opened this issue 1 year ago • 2 comments

NutUI React 包名

@nutui/nutui-react-taro

NutUI React 版本号

^2.0.15

平台

weapp

重现链接

重现步骤

错误代码:

import { getRegionList } from '@/services/common';
import { ArrowRight } from '@nutui/icons-react-taro';
import styles from './index.module.scss';
import { Form, Button, Input, Cascader } from '@nutui/nutui-react-taro';
import { forwardRef, useRef, useState } from 'react';
const FormCascader = forwardRef((props: any, ref) => {
  const { value, ...moreProps } = props;
  return (
    <>
      <div className={styles.line}>
        {value?.length ? (
          <div className={styles.value}>{value?.map((i) => i).join('/')}</div>
        ) : (
          '请选择所在地区'
        )}
        <ArrowRight />
      </div>
      <Cascader
        {...moreProps}
        title="选择所在地区"
        closeable={false}
        ref={ref}
        format={{
          topId: null,
          idKey: 'code',
          pidKey: 'parentCode',
          sortKey: '',
        }}
        optionKey={{
          valueKey: 'name',
          textKey: 'name',
          childrenKey: 'children',
        }}
        lazy
        value={value.map(i=>i)}
        defaultValue={value.map(i=>i)}
        onLoad={(node: any, resolve: (children: any) => void) => {
          if (node.loading === false) {
            return;
          }
          getRegionList(
            node.root
              ? {
                  level: 0,
                }
              : {
                  parentCode: node.code,
                },
          ).then((res) => {
            resolve(res);
          });
        }}
      ></Cascader>
    </>
  );
});
const App = () => {
  const ref = useRef();
  const [value, setValue] = useState();
  return (
    <>
      <Form
        labelPosition="right"
        footer={
          <>
            <Button formType="submit" block type="primary">
              提交
            </Button>
          </>
        }
      >
        <Form.Item
          required
          label="收件人姓名"
          name="name"
          rules={[{ required: true, message: '请输入收件人姓名' }]}
        >
          <Input placeholder="请输入收件人姓名" type="text" />
        </Form.Item>
        <Form.Item
          label="收件人手机号"
          name="phone"
          rules={[
            { required: true, message: '请输入收件人手机号' },
            {
              validator: (_, value) => {
                const reg =
                  /^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[189])\d{8}$/;
                if (reg.test(value)) {
                  return Promise.resolve(true);
                } else {
                  return Promise.reject('请输入收件人手机号');
                }
              },
            },
          ]}
        >
          <Input type="tel" placeholder="请输入收件人手机号" maxLength={11} />
        </Form.Item>
        <Form.Item
          label="所在地区"
          name="picker"
          required
          onClick={(event, ref: any) => {
            ref.open();
          }}
        >
          <FormCascader></FormCascader>
        </Form.Item>
        <Form.Item
          label="详细地址"
          name="addressDetail"
          rules={[{ required: true, message: '请输入详细地址' }]}
        >
          <Input placeholder="请输入详细地址" type="text" />
        </Form.Item>
      </Form>
    </>
  );
};

export default App;

期望的结果是什么?

期望实现代码

import { ArrowRight } from '@nutui/icons-react-taro';
import styles from './index.module.scss';
import { Form, Button, Input, Cascader } from '@nutui/nutui-react-taro';
import { forwardRef, useRef, useState } from 'react';
const FormCascader = forwardRef((props: any, ref) => {
  const { value, ...moreProps } = props;
  return (
    <>
      <div className={styles.line}>
        {value?.length ? (
          <div className={styles.value}>{value?.map((i) => i.text).join('/')}</div>
        ) : (
          '请选择所在地区'
        )}
        <ArrowRight />
      </div>
      <Cascader
        {...moreProps}
        title="选择所在地区"
        closeable={false}
        ref={ref}
        format={{
          topId: null,
          idKey: 'code',
          pidKey: 'parentCode',
          sortKey: '',
        }}
        optionKey={{
          valueKey: 'code',
          textKey: 'name',
          childrenKey: 'children',
        }}
        lazy
        value={value.map(i=>i.value)}
        defaultValue={value.map(i=>i.value)}
        onLoad={(node: any, resolve: (children: any) => void) => {
          if (node.loading === false) {
            return;
          }
          getRegionList(
            node.root
              ? {
                  level: 0,
                }
              : {
                  parentCode: node.value,
                },
          ).then((res) => {
            resolve(res);
          });
        }}
      ></Cascader>
    </>
  );
});
const App = () => {
  return (
    <>
      <Form
        labelPosition="right"
        footer={
          <>
            <Button formType="submit" block type="primary">
              提交
            </Button>
          </>
        }
      >
        <Form.Item
          required
          label="收件人姓名"
          name="name"
          rules={[{ required: true, message: '请输入收件人姓名' }]}
        >
          <Input placeholder="请输入收件人姓名" type="text" />
        </Form.Item>
        <Form.Item
          label="收件人手机号"
          name="phone"
          rules={[
            { required: true, message: '请输入收件人手机号' },
            {
              validator: (_, value) => {
                const reg =
                  /^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[189])\d{8}$/;
                if (reg.test(value)) {
                  return Promise.resolve(true);
                } else {
                  return Promise.reject('请输入收件人手机号');
                }
              },
            },
          ]}
        >
          <Input type="tel" placeholder="请输入收件人手机号" maxLength={11} />
        </Form.Item>
        <Form.Item
          label="所在地区"
          name="picker"
          required
          getValueFromEvent={(...args) => args[1]}
          onClick={(event, ref: any) => {
            ref.open();
          }}
        >
          <FormCascader></FormCascader>
        </Form.Item>
        <Form.Item
          label="详细地址"
          name="addressDetail"
          rules={[{ required: true, message: '请输入详细地址' }]}
        >
          <Input placeholder="请输入详细地址" type="text" />
        </Form.Item>
      </Form>
    </>
  );
};

export default App;

实际的结果是什么?

onChang得到的值 不能发生任何改变,否则不再受控

import { getRegionList } from '@/services/common';
import { ArrowRight } from '@nutui/icons-react-taro';
import styles from './index.module.scss';
import { Form, Button, Input, Cascader } from '@nutui/nutui-react-taro';
import { forwardRef } from 'react';
const FormCascader = forwardRef((props: any, ref) => {
  const { value, ...moreProps } = props;
  return (
    <>
      <div className={styles.line}>
        {value?.length ? (
          <div className={styles.value}>{value?.map((i) => i).join('/')}</div>
        ) : (
          '请选择所在地区'
        )}
        <ArrowRight />
      </div>
      <Cascader
        {...moreProps}
        title="选择所在地区"
        closeable={false}
        ref={ref}
        format={{
          topId: null,
          idKey: 'code',
          pidKey: 'parentCode',
          sortKey: '',
        }}
        optionKey={{
          valueKey: 'name',
          textKey: 'name',
          childrenKey: 'children',
        }}
        lazy
        value={value}
        defaultValue={value}
        onLoad={(node: any, resolve: (children: any) => void) => {
          if (node.loading === false) {
            return;
          }
          getRegionList(
            node.root
              ? {
                  level: 0,
                }
              : {
                  parentCode: node.value,
                },
          ).then((res) => {
            resolve(res);
          });
        }}
      ></Cascader>
    </>
  );
});
const App = () => {
  return (
    <>
      <Form
        labelPosition="right"
        footer={
          <>
            <Button formType="submit" block type="primary">
              提交
            </Button>
          </>
        }
      >
        <Form.Item
          required
          label="收件人姓名"
          name="name"
          rules={[{ required: true, message: '请输入收件人姓名' }]}
        >
          <Input placeholder="请输入收件人姓名" type="text" />
        </Form.Item>
        <Form.Item
          label="收件人手机号"
          name="phone"
          rules={[
            { required: true, message: '请输入收件人手机号' },
            {
              validator: (_, value) => {
                const reg =
                  /^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[189])\d{8}$/;
                if (reg.test(value)) {
                  return Promise.resolve(true);
                } else {
                  return Promise.reject('请输入收件人手机号');
                }
              },
            },
          ]}
        >
          <Input type="tel" placeholder="请输入收件人手机号" maxLength={11} />
        </Form.Item>
        <Form.Item
          label="所在地区"
          name="picker"
          required
          // getValueFromEvent={(...args) => args[1]}
          onClick={(event, ref: any) => {
            ref.open();
          }}
        >
          <FormCascader></FormCascader>
        </Form.Item>
        <Form.Item
          label="详细地址"
          name="addressDetail"
          rules={[{ required: true, message: '请输入详细地址' }]}
        >
          <Input placeholder="请输入详细地址" type="text" />
        </Form.Item>
      </Form>
    </>
  );
};

export default App;

环境信息

No response

其他补充信息

No response

lei14370 avatar Jan 24 '24 04:01 lei14370

你好 @lei14370, 我们需要你提供一个在线的重现实例以便于我们帮你排查问题。你可以通过点击 此处 创建一个 codesandbox 或者提供一个最小化的 GitHub 仓库。请确保选择准确的版本。

github-actions[bot] avatar Jan 26 '24 09:01 github-actions[bot]

受控模式下不能同时设置 value 和 defalutValue,应该只设置 value。 image 你的代码中,应该把 defalutValue 去掉。

oasis-cloud avatar Jan 29 '24 07:01 oasis-cloud