ReactNative 开发时,如何设计一个数据“灵活”的组件呢?

39 天前
 mouyase

在项目中遇到了类似这样的需求。

有一个类似表单的页面,这个页面里的每一个组件的数据源都可能会有以下几种情况。

基本的逻辑就是页面里总是显示最后一个激活的值,但是这种情况下不知道如何设计组件才能达到一个比较好的效果了。

之前试着把数据放进了 ref ,但是这样数据改变又很难刷新,不知道有没有什么好办法来处理呢。

978 次点击
所在节点    问与答
23 条回复
rabbbit
39 天前
没太看懂,要我写就是
1 独立的表单组件,可以传值进来,用户编辑后抛出事件,别的值从哪来、存到哪一律不管。
2 取值、缓存值这些操作独立出来放外面,根据情况看封装个 hook 还是塞到状态管理里啥的。
mouyase
39 天前
@rabbbit

如果传值进来的话,是通过 props 传进来吗?那这个值是不是需要是一个 state ?那我修改 state 的时候,会导致这个组件和父级组件都重新渲染,会导致重复的生命周期。
事件传出去的值是不是也要用 state 保存呢?不然应该如何根据一个组件的值修改另一个组件呢。
huijiewei
39 天前
React 的组件只有 2 种值

1. 外部传入 props 或者 useContext 的跨组件值,这些都是外部值
2. 内部变化 state

你所说的所有情况都可以抽象为这种

当前页面没有任何操作时的初始值
当前页面从外部跳转过来时,使用外部跳转过来的值
-----
上面两种情况是一样的,都是初始值,放在 props 传入


当前页面编辑后,缓存到本地的值
-----
其实就是内部 state 的缓存,这里的缓存看你控制的细粒度了,可以整个表单的 state 缓存,也可以单独组件的 state 缓存,这里抽象会复杂一些,性能要求不高,表单控件不多的话,就用表单缓存


页面里的交互逻辑,比如操作了 A 组件导致 B 组件变化了的值
-----
A 引起 B 变化就是 B 的 props 引入了根据 A 变化的值,这种情况下 B 肯定要重新渲染的


React 的特性需要抽象成最小细粒的组件,以组件为单位渲染即可。

建议使用现成的 Form 组件或者 react-hook-form ,UI 根据数据渲染即可
rabbbit
39 天前
大概这个意思,input 组件啥都不管

import React,{ useState } from 'react';

function MyInput(props) {
return (
<input value={props.value} onInput={(e) => {
props.onInput(e.target.value)
}} />
)
}
export function App(props) {
const [inputValue, setInputValue] = useState('1')
return (
<div className='App'>
<MyInput value={inputValue} onInput={(value) => {
setInputValue(value)
}}/>
</div>
);
}
mouyase
39 天前
@huijiewei 感谢解惑。

如果是操作 A 组件导致 B 组件变换。
<Comp>
<A />
<B />
<C />
<D />
<E />
<F />
</Comp>
如果是这种组件结构的话,A 去修改 B 的 props 值,则需要把 state 放到 Comp 里吧。但是如果是这样,state 就会导致整个 Comp 都会重新渲染,最后导致 CDEF 组件全都重渲染,这种情况有什么好的办法吗。
mouyase
39 天前
@rabbbit 这种情况下,MyInput 每次输入都会导致 App 组件整体重渲染吧。
rabbbit
39 天前
其实没有性能压力表单啥的重新渲染也就渲染了
rabbbit
39 天前
有性能压力的话我就不太清楚了,我这用 vue ,react 写的少。
有性能要求的时候我一般都是直接在 vue 里写原生 js 操作 DOM 或者用 lit 这种 web component 这种。
rabbbit
39 天前
也许 useMemo 能解决你说的子组件被更新的问题
参考一下这个看看?
https://www.v2ex.com/t/854260
wuyiccc
39 天前
用 useMemo 控制一下防止组件重复渲染?
wkmike
39 天前
@mouyase #5 ABCDEF 都用 React.memo 包一下,各自定制 Props 变更判断
mouyase
39 天前
@wkmike 那是不是所有的组件的 props 都要独立成不同的 state 呢,如果所有的 state 都在同一个 Object 里,是不是就无效了?
wkmike
39 天前
@mouyase #12 如果都是外部组件并且接收同样的 Props 比如你说的 state 对象,A 组件根据 state.a 来更新,那你在 React.memo 第二个参数里面只判断 prevProps.state.a 和 nextProps.state.a 是否变化就行了
mouyase
39 天前
@wkmike 是不是只有类组件才能这样处理,如果是函数组件呢
wkmike
39 天前
@mouyase #14 React.memo 就是给 Function Component 实现了类似 Class Component 生命周期 shouldComponentUpdate 方法用来优化性能的高阶组件
rabbbit
39 天前
试着研究了一下,这样倒是不会更新,不过感觉好麻烦

import React,{ useState, memo } from 'react';

function MyInput(props) {
return (
<input value={props.value} onInput={(e) => {
props.onInput(e.target.value)
}} />
)
}

function MyInputB(props) {
return (
<input value={props.value} onInput={(e) => {
props.onInput(e.target.value)
}} />
)
}

const InputBMemo = memo(({value, onInput}) => {
return <MyInputB value={value} onInput={onInput}/>
},(oldProps, newProps) => oldProps.value === newProps.value)

export function App(props) {
const [inputValue, setInputValue] = useState({
a: 1,
b: 2
})

return (
<div className='App'>
<MyInput value={inputValue.a} onInput={(value) => {
setInputValue({
...inputValue,
a: value
})
}}/>

<InputBMemo value={inputValue.b} onInput={(value) => {
setInputValue({
...inputValue,
b: value
})
}}/>
</div>
);
}
wkmike
39 天前
@rabbbit #16 那就组件内用 useMemo 咯,只引用各自用到的 a 和 b ,另外 setInputValue 直接用 prevState

https://gist.github.com/wkmike/e3787e498dd7288e990a96d2cfe5ec3b
Mandmg
39 天前
用 redux 啊..
直接解决了
huijiewei
38 天前
@mouyase C D E F 并不会重新渲染,根组件的渲染不会影响子组件,除非你也改变了子组件的 props ,这就是 React 为啥要细粒度组件的原因
br_wang
38 天前
参考下 ElementUI 或 AntDesign 里 Form 组件的设计,一般内部还是会维护一个 state ,处理编辑的状态记录,还会有类似 isDirty 的 flag 用于标注该项是否由用户编辑过,编辑过就要处理校验等等。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1030401

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX