Skip to main content

表单 (form) in React

类型 (Type)

 1. 受控组件 (controlled component)

值将会同步到state, 并且使用value属性


    1) textarea onChange=handleChange(event: ChangeEvent<HTMLTextAreaElement>)

        event.target.value

    2) input onChange=handleChange(event: ChangeEvent<HTMLInputElement>)

        event.target.value

    3) select onChange=handleChange(event: ChangeEvent<HTMLSelectElement>)


2. 非受控组件 (non-controlled component)

值不会同步到state, 使用defaultValue属性


设计受控组件 (Design controlled component)

每次设计受控组件的时候,要记得放两个属性

1) value={xxx}, onChange={xxx}


We could use hidden input to submit some data

<input type="hidden">


搜索 (Searching & Pagination)

http://xxx/xxx/xx?keyword=xx&page=n

Since after refreshing, content will be lost

Approach to redirect to url with parameters:

const { pathname } = useLocation();
const handleSearch = (value: string) => {
nav({
pathname: pathname,
search: `keyword=${value}`,
});
};


Approach to retrieve url: xxx/xxx?keyword=xx

const [searchParams] = useSearchParams();
console.log("keyword", searchParams.get("keyword"));



Third-party Hooks to set initial form values

const [form] = Form.useForm();
form.setFieldsValue({ username, password });

and should bind this form with original form:

<Form
form={form}
/>


Third-party Hooks to get all form values

form.getFieldsValue()



Third-party form validation tool: 

1) React-Hook-Form

2) Formik


Checkbox

在antd的Form表单中,<Input />组件都是有value属性的, <Checkbox></Checkbox>没有,如何解决?

可以使用valuepropName="checked",来表示 checked代替value属性,放在Form.Item中

e.g.,

<Form.Item name="isCenter" valuePropName="checked">
<Checkbox>居中显示</Checkbox>
</Form.Item>


在提交表单的时候,checkbox有多个选项,如何设置name?

可以使用useState来定义一个selectedValues,每次选中/取消选中 的时候(onChange), 判断当前的checkbox是否在selectedValues里面,如果在,就删除,如果不在,就加入。然后设置checkbox的checked={selecetedValues.includes(value)}


然后使用一个<input type="hidden" value={selectedValues.toString()} /> 隐藏域来提交。


在解决的过程中,我遇到了一个问题: 就是我准备在初始化的时候,将所有默认选中的checkbox选中,我使用了以下的useEffect函数

useEffect(() => { list.forEach(eachItem => { const { value, checked } = eachItem; if (checked) { setSelectedValues(selectedValues.concat(value)); } }) }, [list, selectedValues])

但是这造成了无限循环。因为中途设置了selectedValues数组,然后设置了这个数组的同时又触发了useEffect函数。

可以改成下面的格式: 函数式更新

useEffect(() => {
list.forEach(eachItem => {
const { value, checked } = eachItem;
if (checked) {
setSelectedValues(selectedValues => selectedValues.concat(value));
}
})
}, [list])


什么是函数式更新?

函数式更新就是下面的形式:

setNum(num => num + 1);

会获取最新的state。

在React里面,React会认为对于state的操作是非常频繁的,所以会把很多次的setState合并成一次。那么如果多次调用

const [num, setNum] = useState(1);

setNum(num + 1);

setNum(num + 1);

只会在最初的num上面加一。结果为2

但是如果使用函数式更新的话,可以获取到最新的state

const [num, setNum] = useState(1);

setNum(num => num + 1);

setNum(num => num + 1);

结果为3



Paragraph

在项目中,有Paragraph组件,但是发现 换行的效果不会显示。有三种解决方案。

1) 可以使用dangerouslySetInnerHTML来设置 才能实现换行效果


首先必须在需要换行的地方 之前是"\n",现在改为<br>

然后使用如下格式:

const genHTML = () => {
return { __html: text.replaceAll("\n", "<br>") };
};
//-----------------------------------------------------
<Paragraph
style={{ textAlign: isCenter ? "center" : "start", marginBottom: "0" }}
>
<span dangerouslySetInnerHTML={genHTML()}></span>
</Paragraph>

但是这样很危险,因为别人可以插入


2) 使用split拆分,然后分行渲染

textList.map((c, i) => {

    <span>

        {i == 0 && {<br />}}

        {text}

    </span>

})

但是这样的话 空格无法显示 写多了会被吞并


3) 直接使用style={{ whiteSpace: "pre-wrap"}} 遇到<br>或者\n会自动换行且不吞并空格

whiteSpace属性有五个选项

- normal: 连续的空白符会被合并,换行符会被当作空白符来处理,填充line boxes 行框盒子时是必要

- nowrap: 连续的空白符会被合并,但是文本内的换行符无效

- pre: 连续的空白符会被保留,在遇到换行符或者<br>元素时才会换行

- pre-wrap: 连续的空白符会被保留,在遇到换行符或者<br>,或者需要为了填充(line boxes)行框盒子时才会换行

- pre-line: 连续的空白符会被合并,在遇到换行或者<br>元素,或者需要为了填充行框盒子时会换行

- break-space: 与pre-wrap行为相同,除了行尾会换行



Comments

Popular posts from this blog

Templates

  Template - Polymorphism is the ability of the same code to operate on different types. This ability to operate on multiple types reduces code duplication by allowing the same piece of code to be reused across the different types it can operate on. - Polymorphism comes in a variety of forms. What we are interested in at the moment is parametric polymorphism, meaning that we can write our code so that it is parameterized over what type it operates on.  -That is, we want to declare a type parameter T and replace int with T in the above code. -Then, when we want to call the function, we can specify the type for T and get the function we desire. C++ provides parametric polymorphism through templates. Templated Functions - We can write a templated function by using the keyword template followed by the template parameters in angle brackets (<>). - Unlike function parameters, template parameters may be types, which are specified with typename where the type of the parameter wo...

useMemo的使用场景

 useMemo是用来缓存 计算属性 的。 计算属性是函数的返回值,或者说那些以返回一个值为目标的函数。 有些函数会需要我们手动去点击,有些函数是直接在渲染的时候就执行,在DOM区域被当作属性值一样去使用。后者被称为计算属性。 e.g. const Component = () => { const [ params1 , setParams1 ] = useState ( 0 ); const [ params2 , setParams2 ] = useState ( 0 ); //这种是需要我们手动去调用的函数 const handleFun1 = () => { console . log ( "我需要手动调用,你不点击我不执行" ); setParams1 (( val ) => val + 1 ); }; //这种被称为计算属性,不需要手动调用,在渲染阶段就会执行的。 const computedFun2 = () => { console . log ( "我又执行计算了" ); return params2 ; }; return ( < div onClick = { handleFun1 } > //每次重新渲染的时候我就会执行 computed: { computedFun2 () } </ div > ); }; 上面的代码中,在每次点击div的时候,因为setParams1的缘故,导致params1改变,整个组件都需要重新渲染,也导致comptedFunc2()也需要重新计算。如果computedFunc2的计算量很大,这时候重新计算会比较浪费。 可以使用useMemo: const Com = () => { const [ params1 , setParams1 ] = useState ( 0 ); const [ params2 , setParams2 ] = useState ( 0 ); //这种是需要我们手动去调用的函数 const handleFun1 ...

Valgrind

  Using Valgrind to check memory How to use Valgrind -To valgrind the program, run the valgrind command and give it our program name as an argument. -For example, if we want to run ./myProgram hello 42, we can simply run Valgrind ./myProgram hello 42.  Uninitialized Values -When we run the program, we may use uninitialized values. It needs to be fixed. Valgrind can tell us about the use of uninitialized values. But it only tell when the control flow of the program depends on the unitialized value. For example, uninitialized value appears in the conditional expression of an if, or a loop, or in the switch statement. -If we want to know where the uninitialized value is from, we can use Valgrind    --track-origins=yes ./myProgram -Using -fsanitize=address can find a lot of problems that Memcheck cannot.  -We can use Valgrind with GDB to debug. We can run: --vgdb=full --vgdb-error=0., then Valgrind will stop on the first error that it encounters and give control to ...