在Taro框架、小程序环境中遇到的列表输入抖动问题及解决方法记录
〇、问题介绍
import {View, Image, Button} from '@tarojs/components'
import { AtImagePicker, AtInput } from 'taro-ui'
import Taro from '@tarojs/taro'
import {useEffect, useState} from 'react'
import request from '@/utils/request'
import {file_url} from '@/config'
import Modal from './modal'
import styles from './index.module.less'
const Index = () =>{
/**
* 控制界面的列表信息
*/
// 界面详细信息
const [datas,setDatas] = useState([])
// 改变正在添加的列表的信息
const onChangeLocalData = ({dataIndex,index,value}) =>{
console.log({dataIndex,index,value})
let ds = [...datas]
ds[dataIndex][index].value=value
setDatas(ds)
}
// 再添加一条本地数据组
const addMoreData = () =>{
setDatas([
...datas,
[
{title:'请输入含有手写数字的图片',type:'image',englishName:'image'},
{title:'请输入图片中的数字',type:'int',englishName:'value'}
]
])
}
// 每一组数据
const Lines = ({dataIndex,lines}) =>{
return (
lines.map(({title,type},i)=>(
<View key={i} className={styles.line}>
<View className={styles.title}
onClick={()=>{
console.log({dataIndex,i})
}}
>
{title}
</View>
{type=='image'
?<AtImagePicker
name={'images-'+dataIndex+'-'+i}
files={lines[i].value}
onChange={fs=>onChangeLocalData({
dataIndex,
index:i,
value:fs
})}
/>
:<AtInput
name={'input-'+dataIndex+'-'+i}
value={datas[dataIndex][i].value}
onChange={v=>onChangeLocalData({
dataIndex,
index:i,
value:v
})}
/>}
</View>
))
)
}
/**
* 获取当前界面上的信息
*/
// 获取当前任务信息
const {id,ret} = Taro.getCurrentInstance().router.params
const [task,setTask] = useState({})
useEffect(()=>{
(async function(){
if (!id) {
Taro.showToast({title:'请传入任务编号', icon:'none'})
return
}
let res = await request({url:`/v1/admin/task/detailWithFormat?id=${id}`,method:'get'})
if (res instanceof Error)return
setTask(res.data)
let ds = res.data.dataFormats
for (let i =0;i<ds.length;i++){
ds[i].title = ds[i].tips
}
setDatas([ds])
})()
},[])
return (
<View className={styles.index}>
<View className={styles.datas}>
{
datas.map((lines,dataIndex)=>(
<View key={dataIndex} className={styles.data}>
{/* <AtIcon size='18' value='close' color='red'
onClick={()=>{
delLocalData(dataIndex)
}}
/> */}
<Lines dataIndex={dataIndex} lines={lines} />
</View>
))
}
</View>
<Button className={styles.add} type='primary' onClick={addMoreData}>
添加更多数据
</Button>
</View>
)
}
export default Index
展示的界面如下图所示。操作上,点击添加更多数据,会产生一个新的表单用来填写数据。
现在遇到的问题是:在input上填写一个字符后,光标focus会离开,进而出现抖动的现象。
我觉得在代码中存在的问题是:每填写一项数据,即列表数据中的一项,就需要更改整个数组的地址,所以就会重新刷新界面,进而产生了抖动的现象。
一、解决问题思路
我的解决办法是:将每一组数据抽象成一个组件;在每个组件中控制数据的输入和展示,在主界面的组件中只进行数据的收集,收集到一个大数组中,但是这个数据不进行界面的展示,这样就不会引起整个界面的刷新问题了。
二、解决结果
2.1 Index组件
import { View, Button,Image } from '@tarojs/components'
import Taro from '@tarojs/taro'
import Lines from '../../components/lines'
import styles from './index.module.less'
import { useEffect, useState } from 'react'
// 放在这里的话,就可以记录每一次在本界面进行的操作
let datas = {}
const Index = () =>{
// 初始化当前界面的信息
useEffect(()=>{
datas={}
},[])
// 本界面的列表信息
const [ids, setIDs] = useState([(new Date()).getTime() + '' + Math.floor(Math.random()*10000)])
const addLine = ()=>{
setIDs([
...ids,
(new Date()).getTime() + '' + Math.floor(Math.random()*10000)
])
}
return (
<View className={styles.index}>
<NavBar title='添加本地数据' />
<View className={styles.datas}>
{ids.map(i=>
<Lines key={i} id={i} dataFormat={dataFormat}
onChange={data=>{
datas[i]=data
}}
/>
)}
</View>
<Button className={styles.add} type='primary' onClick={addLine}>
<Image src='https://zhangruiyuan.oss-cn-hangzhou.aliyuncs.com/picGo/images/20211105021700.png'></Image>
添加更多数据
</Button>
</View>
)
}
export default Index
2.2 Lines组件
import {View} from '@tarojs/components'
import { useState } from 'react'
import {AtImagePicker,AtInput,AtForm} from 'taro-ui'
import styles from './index.module.less'
// 每一组数据
const Lines = ({id, dataFormat={}, onChange}) =>{
const [data, setData] = useState({})
return (
<View className={styles.lines}>
{dataFormat.map(({title,type,englishName},i)=>(
<View key={i} className={styles.line}>
<View className={styles.title}>{title}</View>
{type=='image'
?<AtImagePicker
name={id+'-picker-'+i}
files={data[englishName]}
onChange={files=>{
let d = {...data}
d[englishName] = files
setData(d)
onChange&&onChange(d)
}}
/>
:<AtInput
name={id+'-input-'+i}
value={data[englishName]}
onChange={x=>{
let d = {...data}
d[englishName]=x
setData(d)
onChange&&onChange(d)
}}
/>}
</View>
))}
</View>
)
}
export default Lines
四、其他思考的问题
问:react框架,界面有一个按钮,调用这个addline函数。请问输出的结果是什么?
const Index = () =>{
// 这里是代码的位置
return(
<View></View>
)
}
export default Index
答:一直是1 加个1就是2。每次初始化 就是函数重新执行。按下面的方式去防止idx就不会出问题了。
let idx =1;
const Index = () =>{
// 这里是代码的位置
return(
<View></View>
)
}
export default Index